mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-14 19:31:14 +00:00
Add orca-translations Claude skill and PO tool (#16436)
* Add orca-translations Claude skill and PO tool
Add a .claude skill that guides translation passes over the localization/i18n gettext catalogs. It covers the workflow: run gettext, settle new glossary terms, translate in batches, verify, and report.
Includes translation-rules.md, which condenses the placeholder, line-break and glossary rules plus the guidance on review notes.
Also adds scripts/po_tool.py (standard library only). It lists pending entries with glossary hints, validates and applies translations, adding '# AI Translated' and '# Needs human review' comments, and rewrites only the entries it changes. It can also check catalogs, look up existing translations, suggest glossary candidates and update the wiki glossary TSV.
* Let po_tool apply translations by entry id
pending now gives each entry a short id, so a translation file can name
entries by id instead of repeating the English msgid. apply accepts either.
A "review": "" item clears an earlier review note when overwriting an
entry, and check gives each msgfmt run its own temporary output file so
parallel checks do not collide.
* Fill all empty translations
Regenerate the template with run_gettext --full and translate every empty
entry in the 22 catalogs (7,089 entries) with the orca-translations skill,
following the localization glossary, including the new belt printer,
IDEX/IQEX and plugin terms. Every new entry is marked "# AI Translated";
122 also carry "# Needs human review" with what to check.
* Show entry ids in po_tool lookup and search translations
lookup now prints each entry's id, so an entry found there can be
rewritten with apply --overwrite without repeating the English, and
--msgstr searches the translations instead of the msgids, which finds
every entry that still uses a term being changed.
SKILL.md describes how to change an established term: check the
catalog's usage first, update the glossary cell, then rewrite only the
entries where the term has that meaning.
* Fix mistranslated terms and align catalogs with the glossary
Correct labels that the glossary had copied, and the entries that used
them:
- ca: Raft was rendered as the Brim term; it is now "Rai". Exhaust fan,
Monotonic line, Unretract, Slice, Lateral Honeycomb and PA Tower
labels fixed.
- cs: Lightning infill is "Blesk", not "Osvětlení" (illumination).
- sv: Retraction is "Retraktion", not "Reduktion"; Unretract,
Lagerhöjd, Delkylningsfläkt, Utsugsfläkt, Aligned Rectilinear and the
Preset label fixed.
- de: Brim is "Rand" and Skirt is "Umrandung", as most entries already
had them.
- lt: brim entries used the Skirt word "apvadas"; they now use "kraštas".
- es: Sparse infill is "relleno de baja densidad", the catalog majority.
- eu: nozzle wipe is "garbiketa", not purge.
- th: the project plate is "เพลต", distinct from the bed.
- uk: Quarter Cubic, Latin "PA" in PA Tower, and Belt purge tower.
- pl: Cross Hatch, Tri-hexagon, Volumetric speed and Raft labels.
- zh_TW: Brim stays "Brim", as the existing labels have it.
- tr: "Prime Tower" read "Prime Minister Tower".
- ko: the plugin "Capabilities" label read "performance".
- Build Volume labels fixed in tr, de, cs and eu.
All 242 rewritten entries are marked "# AI Translated".
* Make more UI text translatable and fix pluralization and context
Audit the sources for text that translators could not translate
correctly and fix it.
Mark text that reached users in English only: IDEX/IQEX role names,
plugin permission prompts and errors, 3MF/preset loading errors, G-code
placeholder parser errors, calibration and device messages, notification
texts, file dialog filters, and the config validation messages.
Replace sentences built from translated fragments, such as the prime
tower warnings, "left"/"right" nozzle names, and "Filament " + number,
with single msgids that have placeholders, so translators can reorder
and inflect them.
Use plural forms for texts with a count ("%1% mixed filaments",
"%d objects", "%1% triangles") instead of "(s)" and mismatched verbs.
Fix the swapped singular/plural pair in "The following presets inherit
this preset".
Add translation contexts where one English word has several meanings
(Subscribed/Local, Standard, Pause, View, Step, Model, Camera, Flow,
Filter, Others, Prepare, the Design tools). Show "Size" instead of
"Build Volume" in the Cut tool, which displays the object size.
Fix code that compared translated text with English (the Edit G-code
dialog group, the plugin registration failure check), and add the
bundled web pages' missing string-table entries. Use the single
character for degrees Celsius, say "G-code", and describe the head
filament map without internal jargon.
Install the libslic3r translate callback before the presets load, so
their load errors are translated, and list the 28 source files that had
marked strings but were never extracted into localization/i18n/list.txt.
* Suggest earlier translations and list fuzzy entries in po_tool pending
pending now attaches the closest earlier translation of a similar
English text (from obsolete or translated entries), so a reworded or
split string keeps its wording, and it lists fuzzy entries by default,
since users never see them. A fuzzy entry also carries its stale
translation as previous_translation.
* Fix wording of the non-boolean operands error
The logical operation error said "operators" where it means the
operands the operation was applied to.
* Translate the newly translatable strings in all languages
Regenerate the template after the translatability changes and fill every
new or changed entry in the 22 catalogs (about 12,800 entries): the
strings that became translatable, the plural forms, the entries split by
context, and the previously fuzzy singular entries that became plurals.
Every new entry is marked "# AI Translated", and about 360 also carry a
"# Needs human review" note saying what to check. Terms follow the
localization glossary. Earlier translations of reworded strings were
reused where the meaning was unchanged. Existing entries were not
changed, and obsolete entries are kept.
* Document the source translatability audit in the orca-translations skill
Add a reference describing how strings reach translators, what to look
for (untranslated text, spliced sentences, missing plurals, ambiguous
words), what not to translate, where a context cannot be carried, and
what to do after the edits, plus a scanner that lists untranslated
user-facing string literals.
* Document how to write translatable strings in AGENTS.md
Tell developers to keep each message complete in one msgid: use
placeholders instead of concatenating translated fragments, plural forms
for counts, and contexts for ambiguous words, and to list new source
files in localization/i18n/list.txt. Add a matching code review item.
* Translate the strings added since the rebase
Regenerate the template against the current main and translate the 26
new entries per language: the Fix Model commands and messages, and the
texture displacement image adjustment panel. Each new entry is marked
"# AI Translated"; existing entries are unchanged.
* tidy
This commit is contained in:
@@ -166,7 +166,7 @@ void Print::_plan_belt_purge()
|
||||
m_wipe_tower_data.tool_ordering.sort_and_build_data(*this, (unsigned int) -1, false);
|
||||
|
||||
if (m_wipe_tower_data.tool_ordering.empty() || m_wipe_tower_data.tool_ordering.last_extruder() == unsigned(-1))
|
||||
throw Slic3r::SlicingError("The print is empty. The model is not printable with current print settings.");
|
||||
throw Slic3r::SlicingError(_u8L("The print is empty. The model is not printable with current print settings."));
|
||||
|
||||
// Is there any filament change at all? Not ToolOrdering::has_wipe_tower(): that reads the
|
||||
// FIRST layer's flag, and on a belt the first layer may be a brim apron band, which carries
|
||||
|
||||
@@ -1807,7 +1807,8 @@ std::vector<std::pair<std::string, SketchPlane>> CadDocument::resolve_datum_plan
|
||||
|
||||
}
|
||||
|
||||
out.emplace_back(base_missing ? f.name + " (base plane missing)" : f.name, result);
|
||||
// TRN Datum plane entry in the reference plane list. %1% is the plane name.
|
||||
out.emplace_back(base_missing ? format(_u8L("%1% (base plane missing)"), f.name) : f.name, result);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -2090,8 +2091,8 @@ static int pick_body(int ref, int nb)
|
||||
{
|
||||
if (ref == -1) return nb - 1;
|
||||
if (ref < 0 || ref >= nb)
|
||||
throw std::runtime_error("a feature works on body " + std::to_string(ref + 1)
|
||||
+ ", which does not exist at that point in the history");
|
||||
throw std::runtime_error(format(_u8L("a feature works on body %1%, which does not exist at that point in the history"),
|
||||
ref + 1));
|
||||
return ref;
|
||||
}
|
||||
|
||||
@@ -2154,11 +2155,11 @@ static void settle_body_refs(CadFeature& f, const std::vector<CadBody>& v, bool
|
||||
CadFeature::BodyId& id = f.body_ref_ids[k++];
|
||||
if (kind != running) return;
|
||||
if (ref == kBodyGone)
|
||||
throw std::runtime_error("\"" + f.name + "\" works on a body made by a feature that was deleted or hidden");
|
||||
throw std::runtime_error(format(_u8L("\"%1%\" works on a body made by a feature that was deleted or hidden"), f.name));
|
||||
if (f.body_refs_pending && id.src >= 0) {
|
||||
const int i = find_body(v, id);
|
||||
if (i < 0)
|
||||
throw std::runtime_error("\"" + f.name + "\" works on a body that does not exist at that point in the history");
|
||||
throw std::runtime_error(format(_u8L("\"%1%\" works on a body that does not exist at that point in the history"), f.name));
|
||||
ref = i;
|
||||
}
|
||||
id = ref >= 0 ? body_id_of(v, ref) : CadFeature::BodyId{};
|
||||
@@ -2384,7 +2385,8 @@ bool CadDocument::move_feature(int index, int delta)
|
||||
check(f.sketch_ref); check(f.sweep_path_ref); check(f.pattern_curve_sketch); check(f.rib_sketch_ref);
|
||||
for (int& r : f.loft_profile_refs) check(r);
|
||||
if (!bad.empty()) {
|
||||
error = "\"" + f.name + "\" uses \"" + bad + "\", so it cannot come before it";
|
||||
// TRN Feature reorder error. %1% is the moved feature, %2% the feature it depends on.
|
||||
error = format(_u8L("\"%1%\" uses \"%2%\", so it cannot come before it"), f.name, bad);
|
||||
features.swap(snapshot);
|
||||
return false;
|
||||
}
|
||||
@@ -2463,7 +2465,8 @@ static std::string open_loop_message(const CadFeature& sketch,
|
||||
for (size_t i = 0; i < shown; ++i)
|
||||
msg += "\n " + format(_u8L("Open at (%.3f, %.3f)"), open[i].x(), open[i].y());
|
||||
if (open.size() > shown)
|
||||
msg += "\n " + format(_u8L("...and %1% more open end(s)"), open.size() - shown);
|
||||
// TRN Follows a list of open sketch ends. %1% is how many more were not listed.
|
||||
msg += "\n " + format(_u8L("Open ends not shown: %1%"), open.size() - shown);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
@@ -2475,11 +2478,11 @@ static gp_Ax1 revolve_axis_of(const CadFeature& f, const CadFeature& sk)
|
||||
if (f.revolve_axis_entity >= 0) {
|
||||
if (f.revolve_axis_entity >= int(sk.entities.size())
|
||||
|| sk.entities[f.revolve_axis_entity].type != SketchEntity::Type::Line)
|
||||
throw std::runtime_error("revolve: the axis line is no longer in the sketch — pick the axis again");
|
||||
throw std::runtime_error(_u8L("revolve: the axis line is no longer in the sketch — pick the axis again"));
|
||||
const SketchEntity& e = sk.entities[f.revolve_axis_entity];
|
||||
const Vec3d a = sk.plane.to_world(e.p0), b = sk.plane.to_world(e.p1);
|
||||
if ((b - a).norm() < 1e-9)
|
||||
throw std::runtime_error("revolve: the axis line has no length");
|
||||
throw std::runtime_error(_u8L("revolve: the axis line has no length"));
|
||||
const Vec3d d = (b - a).normalized();
|
||||
return gp_Ax1(gp_Pnt(a.x(), a.y(), a.z()), gp_Dir(d.x(), d.y(), d.z()));
|
||||
}
|
||||
@@ -3024,17 +3027,17 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
|
||||
// ISO external thread depth is ~0.61*P, so allow up to 0.7*P (0.49 wrongly rejected
|
||||
// every real thread -> nothing rendered). Still bound it well under a full pitch.
|
||||
// R >= 0.5 (not >): M1, the smallest size in the standards table, is exactly 0.5.
|
||||
const char* why = R < 0.5 ? "thread: the diameter must be at least 1 mm"
|
||||
: P <= 0.1 ? "thread: the pitch must be more than 0.1 mm"
|
||||
: (D <= 1e-3 || D >= 0.7 * P) ? "thread: the depth must be between 0 and 0.7 x the pitch"
|
||||
: D >= 0.45 * R ? "thread: the depth is too large for this diameter"
|
||||
: H <= 0.5 * P ? "thread: the length must be more than half a pitch"
|
||||
: H / P >= 400.0 ? "thread: too many turns (length / pitch must stay under 400)"
|
||||
const char* why = R < 0.5 ? L("thread: the diameter must be at least 1 mm")
|
||||
: P <= 0.1 ? L("thread: the pitch must be more than 0.1 mm")
|
||||
: (D <= 1e-3 || D >= 0.7 * P) ? L("thread: the depth must be between 0 and 0.7 x the pitch")
|
||||
: D >= 0.45 * R ? L("thread: the depth is too large for this diameter")
|
||||
: H <= 0.5 * P ? L("thread: the length must be more than half a pitch")
|
||||
: H / P >= 400.0 ? L("thread: too many turns (length / pitch must stay under 400)")
|
||||
: nullptr;
|
||||
// Legacy recipes keep their old outcome (the body left as it was) so a project that
|
||||
// opened before still opens; every thread made now reports the reason instead.
|
||||
if (why != nullptr) {
|
||||
if (f.thread_major_nominal) throw std::runtime_error(why);
|
||||
if (f.thread_major_nominal) throw std::runtime_error(Slic3r::I18N::translate(why));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3078,7 +3081,7 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
|
||||
// Tapped hole: bore to the minor radius R - D, then cut the groove out to the
|
||||
// major radius R. The bore sits 10 um inside the minor radius so that, threading
|
||||
// an existing tap-drill hole, it does not coincide with that hole's wall.
|
||||
if (!have_body) throw std::runtime_error("internal thread needs a body");
|
||||
if (!have_body) throw std::runtime_error(_u8L("internal thread needs a body"));
|
||||
const double bore_r = R - D - 0.01;
|
||||
cut_from(result, BRepPrimAPI_MakeCylinder(ax2, bore_r, f.thread_height).Shape());
|
||||
TopoDS_Shape groove;
|
||||
@@ -3241,12 +3244,12 @@ void CadDocument::apply_boolean(std::vector<CadBody>& bodies, const CadFeature&
|
||||
const int tool = f.bool_tool_body == -1 ? -1 : pick_body(f.bool_tool_body, nb);
|
||||
// Same rule as Cut, Mirror and Transform: an operation that cannot run says why, rather
|
||||
// than leaving the bodies as they were and reporting success.
|
||||
if (tgt < 0) throw std::runtime_error("boolean: no target body");
|
||||
if (tool < 0) throw std::runtime_error("boolean: no tool body — pick a second body");
|
||||
if (tgt == tool) throw std::runtime_error("boolean: the target and the tool are the same body");
|
||||
if (tgt < 0) throw std::runtime_error(_u8L("boolean: no target body"));
|
||||
if (tool < 0) throw std::runtime_error(_u8L("boolean: no tool body — pick a second body"));
|
||||
if (tgt == tool) throw std::runtime_error(_u8L("boolean: the target and the tool are the same body"));
|
||||
const TopoDS_Shape A = bodies[tgt].shape; // target survives
|
||||
const TopoDS_Shape B = bodies[tool].shape; // tool, consumed unless kept
|
||||
if (A.IsNull() || B.IsNull()) throw std::runtime_error("boolean: a body has no geometry");
|
||||
if (A.IsNull() || B.IsNull()) throw std::runtime_error(_u8L("boolean: a body has no geometry"));
|
||||
|
||||
NCollection_List<TopoDS_Shape> args, tools;
|
||||
args.Append(A);
|
||||
@@ -3554,7 +3557,7 @@ void CadDocument::apply_thicken_surface(std::vector<CadBody>& bodies, const CadF
|
||||
if (props.Mass() < 0.0) solid.Reverse();
|
||||
}
|
||||
|
||||
bodies.push_back({solid, f.name.empty() ? std::string("ThickenSurface") : f.name});
|
||||
bodies.push_back({solid, f.name.empty() ? _u8L("Thicken Surface") : f.name});
|
||||
}
|
||||
|
||||
void CadDocument::apply_surface_offset(std::vector<CadBody>& bodies, const CadFeature& f) const
|
||||
@@ -3573,7 +3576,7 @@ void CadDocument::apply_surface_offset(std::vector<CadBody>& bodies, const CadFe
|
||||
TopoDS_Shape off_shape = mos.Shape();
|
||||
if (off_shape.IsNull()) throw std::runtime_error(_u8L("surface-offset: produced no geometry"));
|
||||
|
||||
bodies.push_back({off_shape, f.name.empty() ? std::string("SurfaceOffset") : f.name});
|
||||
bodies.push_back({off_shape, f.name.empty() ? _u8L("Surface Offset") : f.name});
|
||||
}
|
||||
|
||||
// Project `edges` of a shape onto `plane`, appending the resulting 2D entities to `out`.
|
||||
|
||||
@@ -325,10 +325,10 @@ std::vector<TopoDS_Edge> GeometryEngine::collect_edges(const TopoDS_Shape& solid
|
||||
// handing the solid back unchanged, which recompute then reported as a success.
|
||||
TopoDS_Shape GeometryEngine::apply_fillet(const TopoDS_Shape& solid, double radius, FaceGroup faces)
|
||||
{
|
||||
if (radius <= 0.001) throw std::runtime_error("the fillet radius must be greater than 0");
|
||||
if (radius <= 0.001) throw std::runtime_error(_u8L("the fillet radius must be greater than 0"));
|
||||
|
||||
std::vector<TopoDS_Edge> edges = collect_edges(solid, faces);
|
||||
if (edges.empty()) throw std::runtime_error("no edges to fillet in that group");
|
||||
if (edges.empty()) throw std::runtime_error(_u8L("no edges to fillet in that group"));
|
||||
|
||||
BRepFilletAPI_MakeFillet fillet(solid);
|
||||
for (const auto& edge : edges)
|
||||
@@ -344,10 +344,10 @@ TopoDS_Shape GeometryEngine::apply_fillet(const TopoDS_Shape& solid, double radi
|
||||
|
||||
TopoDS_Shape GeometryEngine::apply_chamfer(const TopoDS_Shape& solid, double distance, FaceGroup faces)
|
||||
{
|
||||
if (distance <= 0.001) throw std::runtime_error("the chamfer distance must be greater than 0");
|
||||
if (distance <= 0.001) throw std::runtime_error(_u8L("the chamfer distance must be greater than 0"));
|
||||
|
||||
std::vector<TopoDS_Edge> edges = collect_edges(solid, faces);
|
||||
if (edges.empty()) throw std::runtime_error("no edges to chamfer in that group");
|
||||
if (edges.empty()) throw std::runtime_error(_u8L("no edges to chamfer in that group"));
|
||||
|
||||
BRepFilletAPI_MakeChamfer chamfer(solid);
|
||||
for (const auto& edge : edges)
|
||||
@@ -370,7 +370,7 @@ TopoDS_Shape GeometryEngine::apply_chamfer(const TopoDS_Shape& solid, double dis
|
||||
|
||||
TopoDS_Shape GeometryEngine::apply_fillet(const TopoDS_Shape& solid, double radius, const std::vector<int>& edge_ids)
|
||||
{
|
||||
if (radius <= 0.001) throw std::runtime_error("the fillet radius must be greater than 0");
|
||||
if (radius <= 0.001) throw std::runtime_error(_u8L("the fillet radius must be greater than 0"));
|
||||
if (edge_ids.empty()) throw std::runtime_error("apply_fillet: no edge picked");
|
||||
|
||||
BRepFilletAPI_MakeFillet mk(solid);
|
||||
@@ -387,7 +387,7 @@ TopoDS_Shape GeometryEngine::apply_fillet(const TopoDS_Shape& solid, double radi
|
||||
|
||||
TopoDS_Shape GeometryEngine::apply_chamfer(const TopoDS_Shape& solid, double distance, const std::vector<int>& edge_ids)
|
||||
{
|
||||
if (distance <= 0.001) throw std::runtime_error("the chamfer distance must be greater than 0");
|
||||
if (distance <= 0.001) throw std::runtime_error(_u8L("the chamfer distance must be greater than 0"));
|
||||
if (edge_ids.empty()) throw std::runtime_error("apply_chamfer: no edge picked");
|
||||
|
||||
BRepFilletAPI_MakeChamfer mk(solid);
|
||||
|
||||
@@ -379,7 +379,7 @@ TopoDS_Shape SketchEngine::make_revolve(const TopoDS_Wire& wire, const gp_Ax1& a
|
||||
}
|
||||
}
|
||||
if (pos && neg)
|
||||
throw std::runtime_error("the profile crosses the revolve axis — it must lie on one side of it");
|
||||
throw std::runtime_error(_u8L("the profile crosses the revolve axis — it must lie on one side of it"));
|
||||
}
|
||||
gp_Ax1 axis = axis_in;
|
||||
double angle_rad = angle_deg * M_PI / 180.0;
|
||||
@@ -390,7 +390,7 @@ TopoDS_Shape SketchEngine::make_revolve(const TopoDS_Wire& wire, const gp_Ax1& a
|
||||
if (!rev.IsDone())
|
||||
throw std::runtime_error(_u8L("Failed to revolve"));
|
||||
if (!BRepCheck_Analyzer(rev.Shape()).IsValid())
|
||||
throw std::runtime_error("the profile crosses the revolve axis — it must lie on one side of it");
|
||||
throw std::runtime_error(_u8L("the profile crosses the revolve axis — it must lie on one side of it"));
|
||||
return rev.Shape();
|
||||
}
|
||||
|
||||
@@ -923,7 +923,7 @@ static TopoDS_Face checked_profile_face(const TopoDS_Face& f)
|
||||
{
|
||||
BRepCheck_Analyzer an(f);
|
||||
if (!an.IsValid())
|
||||
throw std::runtime_error("the profile crosses or folds back on itself, so it does not bound one region");
|
||||
throw std::runtime_error(_u8L("the profile crosses or folds back on itself, so it does not bound one region"));
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Exception.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "format.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "LocalesUtils.hpp"
|
||||
#include "Preset.hpp"
|
||||
@@ -613,7 +614,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src,
|
||||
void ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, ConfigSubstitutionContext& substitutions_ctxt, bool append)
|
||||
{
|
||||
if (! this->set_deserialize_nothrow(opt_key_src, value_src, substitutions_ctxt, append))
|
||||
throw BadOptionValueException(format("Invalid value provided for parameter %1%: %2%", opt_key_src, value_src));
|
||||
throw BadOptionValueException(format(_u8L("Invalid value provided for parameter %1%: %2%"), opt_key_src, value_src));
|
||||
}
|
||||
|
||||
void ConfigBase::set_deserialize(std::initializer_list<SetDeserializeItem> items, ConfigSubstitutionContext& substitutions_ctxt)
|
||||
@@ -1173,7 +1174,7 @@ ConfigSubstitutions ConfigBase::load_from_ini(const std::string &file, ForwardCo
|
||||
boost::property_tree::read_ini(ifs, tree);
|
||||
return this->load(tree, compatibility_rule);
|
||||
} catch (const ConfigurationError &e) {
|
||||
throw ConfigurationError(format("Failed loading configuration file \"%1%\": %2%", file, e.what()));
|
||||
throw ConfigurationError(format(_u8L("Failed loading configuration file \"%1%\": %2%"), file, e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1430,9 +1431,8 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo
|
||||
}
|
||||
}
|
||||
if (!header_found) {
|
||||
std::string error_message = "Not a gcode file generated by ";
|
||||
error_message += SLIC3R_APP_FULL_NAME;
|
||||
error_message += ".";
|
||||
// TRN %1% is the application name.
|
||||
std::string error_message = format(_u8L("Not a gcode file generated by %1%."), SLIC3R_APP_FULL_NAME);
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << error_message;
|
||||
throw Slic3r::RuntimeError(error_message.c_str());
|
||||
}
|
||||
@@ -1458,7 +1458,8 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo
|
||||
}
|
||||
if (!begin_found) {
|
||||
//BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << format("Configuration block closing tag \"; CONFIG_BLOCK_START\" not found when reading %1%", file);
|
||||
throw Slic3r::RuntimeError(format("Config tag \"; CONFIG_BLOCK_START\" not found"));
|
||||
// TRN %1% is a tag in the G-code file that must not be translated.
|
||||
throw Slic3r::RuntimeError(format(_u8L("Config tag \"%1%\" not found"), "; CONFIG_BLOCK_START"));
|
||||
}
|
||||
std::string key, value;
|
||||
while (std::getline(ifs, line)) {
|
||||
@@ -1483,7 +1484,7 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo
|
||||
}
|
||||
if (!end_found) {
|
||||
//BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << format("Configuration block opening tag \"; CONFIG_BLOCK_END\" not found when reading %1%", file);
|
||||
throw Slic3r::RuntimeError(format("Config tag \"; CONFIG_BLOCK_END\" not found"));
|
||||
throw Slic3r::RuntimeError(format(_u8L("Config tag \"%1%\" not found"), "; CONFIG_BLOCK_END"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1503,7 +1504,7 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo
|
||||
|
||||
if (key_value_pairs < 80) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs);
|
||||
throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs));
|
||||
throw Slic3r::RuntimeError(format(_u8L("Suspiciously low number of configuration values extracted from %1%: %2%"), file, key_value_pairs));
|
||||
}
|
||||
|
||||
// Do legacy conversion on a completely loaded dictionary.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "Config.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -124,9 +125,9 @@ double Extruder::unretract()
|
||||
void Extruder::set_retracted(double retracted, double restart_extra)
|
||||
{
|
||||
if (retracted < - EPSILON)
|
||||
throw Slic3r::RuntimeError("Custom G-code reports negative z_retracted.");
|
||||
throw Slic3r::RuntimeError(_u8L("Custom G-code reports negative z_retracted."));
|
||||
if (restart_extra < - EPSILON)
|
||||
throw Slic3r::RuntimeError("Custom G-code reports negative z_restart_extra.");
|
||||
throw Slic3r::RuntimeError(_u8L("Custom G-code reports negative z_restart_extra."));
|
||||
|
||||
if (retracted > EPSILON) {
|
||||
m_retracted = retracted;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "ColorDecomposeRecipe.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "format.hpp"
|
||||
#include "FilamentMixerModel.hpp"
|
||||
#include "LocalesUtils.hpp"
|
||||
|
||||
@@ -633,36 +635,36 @@ bool try_parse_mixed_components_strict(const std::string &str,
|
||||
{
|
||||
components.clear();
|
||||
if (str.empty()) {
|
||||
err = "empty component list";
|
||||
err = _u8L("empty component list");
|
||||
return false;
|
||||
}
|
||||
std::istringstream ss(str);
|
||||
std::string token;
|
||||
while (std::getline(ss, token, ',')) {
|
||||
if (token.empty()) {
|
||||
err = "empty component index";
|
||||
err = _u8L("empty component index");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const long val = std::stol(token);
|
||||
if (val < 1) {
|
||||
err = "component index must be >= 1 (got " + token + ")";
|
||||
err = format(_u8L("component index must be >= 1 (got %1%)"), token);
|
||||
return false;
|
||||
}
|
||||
components.push_back(static_cast<unsigned int>(val));
|
||||
} catch (...) {
|
||||
err = "invalid component index \"" + token + "\"";
|
||||
err = format(_u8L("invalid component index \"%1%\""), token);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (components.size() < 2) {
|
||||
err = "at least 2 components required (got " + std::to_string(components.size()) + ")";
|
||||
err = format(_u8L("at least 2 components required (got %1%)"), components.size());
|
||||
return false;
|
||||
}
|
||||
std::set<unsigned int> seen;
|
||||
for (unsigned int c : components) {
|
||||
if (!seen.insert(c).second) {
|
||||
err = "duplicate component index " + std::to_string(c);
|
||||
err = format(_u8L("duplicate component index %1%"), c);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -682,24 +684,24 @@ bool try_parse_mixed_ratios_strict(const std::string &str,
|
||||
std::string token;
|
||||
while (std::getline(ss, token, ',')) {
|
||||
if (token.empty()) {
|
||||
err = "empty ratio value";
|
||||
err = _u8L("empty ratio value");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const double val = std::stod(token);
|
||||
if (!(val > 0.0)) {
|
||||
err = "ratio must be positive (got " + token + ")";
|
||||
err = format(_u8L("ratio must be positive (got %1%)"), token);
|
||||
return false;
|
||||
}
|
||||
ratios.push_back(val);
|
||||
} catch (...) {
|
||||
err = "invalid ratio \"" + token + "\"";
|
||||
err = format(_u8L("invalid ratio \"%1%\""), token);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (ratios.size() != n_components) {
|
||||
err = "expected " + std::to_string(n_components) + " ratio(s), got "
|
||||
+ std::to_string(ratios.size());
|
||||
// TRN %1% is the expected number of ratios, %2% the number found.
|
||||
err = format(_u8L("the ratio count must match the component count: expected %1%, got %2%"), n_components, ratios.size());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -713,11 +715,11 @@ bool validate_gradient_range_strict(const std::string &str, std::string &err)
|
||||
CNumericLocalesSetter c_locale_setter;
|
||||
float v0 = 0.f, v1 = 0.f;
|
||||
if (std::sscanf(str.c_str(), "%f,%f", &v0, &v1) != 2) {
|
||||
err = "expected two comma-separated floats, e.g. \"0.10,0.90\"";
|
||||
err = _u8L("expected two comma-separated floats, e.g. \"0.10,0.90\"");
|
||||
return false;
|
||||
}
|
||||
if (!(v0 > 0.f && v0 < 1.f && v1 > 0.f && v1 < 1.f)) {
|
||||
err = "start and end ratios must be in (0, 1)";
|
||||
err = _u8L("start and end ratios must be in (0, 1)");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -771,8 +773,7 @@ static void check_mixed_array_size_required(std::map<std::string, std::string> &
|
||||
{
|
||||
if (actual_size != expected_size) {
|
||||
append_error(errors, opt_key,
|
||||
"array size " + std::to_string(actual_size)
|
||||
+ " does not match filament slot count " + std::to_string(expected_size));
|
||||
format(_u8L("array size %1% does not match filament slot count %2%"), actual_size, expected_size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -789,7 +790,7 @@ std::map<std::string, std::string> validate_mixed_filament_params(
|
||||
if (has_mixed_sub_params_specified(comp_strs, ratio_strs, gradient_flags)
|
||||
&& !has_any_mixed_filament(is_mixed)) {
|
||||
append_error(errors, "filament_is_mixed",
|
||||
"must be set when mixed filament parameters are specified");
|
||||
_u8L("must be set when mixed filament parameters are specified"));
|
||||
return errors;
|
||||
}
|
||||
|
||||
@@ -822,34 +823,33 @@ std::map<std::string, std::string> validate_mixed_filament_params(
|
||||
if (!is_mixed[i])
|
||||
continue;
|
||||
|
||||
const std::string slot = "slot " + std::to_string(i + 1);
|
||||
const size_t slot = i + 1;
|
||||
const std::string comp_str = i < comp_strs.size() ? comp_strs[i] : "";
|
||||
|
||||
std::vector<unsigned int> components;
|
||||
std::string comp_err;
|
||||
if (!try_parse_mixed_components_strict(comp_str, components, comp_err)) {
|
||||
append_error(errors, "filament_mixed_components", slot + ": " + comp_err);
|
||||
// TRN Mixed filament validation error. %1% is the filament slot number, %2% the reason.
|
||||
append_error(errors, "filament_mixed_components", format(_u8L("slot %1%: %2%"), slot, comp_err));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned int c : components) {
|
||||
if (c > num_physical) {
|
||||
append_error(errors, "filament_mixed_components",
|
||||
slot + ": component " + std::to_string(c)
|
||||
+ " out of range (max physical filament index is "
|
||||
+ std::to_string(num_physical) + ")");
|
||||
format(_u8L("slot %1%: component %2% out of range (max physical filament index is %3%)"),
|
||||
slot, c, num_physical));
|
||||
break;
|
||||
}
|
||||
if (c == i + 1) {
|
||||
append_error(errors, "filament_mixed_components",
|
||||
slot + ": cannot reference itself as a component");
|
||||
format(_u8L("slot %1%: cannot reference itself as a component"), slot));
|
||||
break;
|
||||
}
|
||||
const size_t idx0 = static_cast<size_t>(c - 1);
|
||||
if (idx0 < is_mixed.size() && is_mixed[idx0]) {
|
||||
append_error(errors, "filament_mixed_components",
|
||||
slot + ": component " + std::to_string(c)
|
||||
+ " references a mixed filament slot");
|
||||
format(_u8L("slot %1%: component %2% references a mixed filament slot"), slot, c));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -857,27 +857,27 @@ std::map<std::string, std::string> validate_mixed_filament_params(
|
||||
std::string ratio_err;
|
||||
const std::string ratio_str = i < ratio_strs.size() ? ratio_strs[i] : "";
|
||||
if (!try_parse_mixed_ratios_strict(ratio_str, components.size(), ratio_err))
|
||||
append_error(errors, "filament_mixed_sublayer_ratios", slot + ": " + ratio_err);
|
||||
append_error(errors, "filament_mixed_sublayer_ratios", format(_u8L("slot %1%: %2%"), slot, ratio_err));
|
||||
|
||||
const bool gradient_on = i < gradient_flags.size() && gradient_flags[i];
|
||||
if (gradient_on) {
|
||||
if (components.size() != 2) {
|
||||
append_error(errors, "filament_mixed_gradient",
|
||||
slot + ": gradient requires exactly 2 components");
|
||||
format(_u8L("slot %1%: gradient requires exactly 2 components"), slot));
|
||||
}
|
||||
|
||||
if (gradient_specified) {
|
||||
std::string range_err;
|
||||
const std::string range_str = i < gradient_range_strs.size() ? gradient_range_strs[i] : "";
|
||||
if (!validate_gradient_range_strict(range_str, range_err))
|
||||
append_error(errors, "filament_mixed_gradient_range", slot + ": " + range_err);
|
||||
append_error(errors, "filament_mixed_gradient_range", format(_u8L("slot %1%: %2%"), slot, range_err));
|
||||
}
|
||||
|
||||
if (curve_specified) {
|
||||
const std::string curve_str = i < gradient_curve_strs.size() ? gradient_curve_strs[i] : "";
|
||||
if (!curve_str.empty() && parse_gradient_curve(curve_str).empty())
|
||||
append_error(errors, "filament_mixed_gradient_curve",
|
||||
slot + ": invalid curve (need at least 2 valid control points)");
|
||||
format(_u8L("slot %1%: invalid curve (need at least 2 valid control points)"), slot));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <string>
|
||||
#include <math.h>
|
||||
#include "PrintConfig.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
// Mark string for localization and translate.
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
@@ -17,10 +18,10 @@
|
||||
namespace Slic3r {
|
||||
|
||||
FlowErrorNegativeSpacing::FlowErrorNegativeSpacing() :
|
||||
FlowError("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?") {}
|
||||
FlowError(L("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?")) {}
|
||||
|
||||
FlowErrorNegativeFlow::FlowErrorNegativeFlow() :
|
||||
FlowError("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?") {}
|
||||
FlowError(L("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?")) {}
|
||||
|
||||
// This static method returns a sane extrusion width default.
|
||||
float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter)
|
||||
@@ -66,7 +67,8 @@ static inline FlowRole opt_key_to_flow_role(const std::string &opt_key)
|
||||
|
||||
static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key)
|
||||
{
|
||||
throw FlowErrorMissingVariable((boost::format("Failed to calculate line width of %1%. Cannot get value of \u201c%2%\u201d.") % opt_key % dependent_opt_key).str());
|
||||
// TRN %1% and %2% are names of settings.
|
||||
throw FlowErrorMissingVariable((boost::format(L("Failed to calculate line width of %1%. Cannot get value of \"%2%\".")) % opt_key % dependent_opt_key).str());
|
||||
}
|
||||
|
||||
// Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser.
|
||||
@@ -162,7 +164,7 @@ Flow Flow::with_spacing(float new_spacing) const
|
||||
assert(m_width >= m_height);
|
||||
out.m_width += new_spacing - m_spacing;
|
||||
if (out.m_width < out.m_height)
|
||||
throw Slic3r::InvalidArgument("Invalid spacing supplied to Flow::with_spacing(), check your layer height and extrusion width.");
|
||||
throw Slic3r::InvalidArgument(L("Invalid spacing supplied to Flow::with_spacing(), check your layer height and extrusion width."));
|
||||
}
|
||||
out.m_spacing = new_spacing;
|
||||
return out;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Thread.hpp"
|
||||
#include "libslic3r/I18N.hpp"
|
||||
|
||||
#include "STEP.hpp"
|
||||
|
||||
@@ -68,7 +69,7 @@ bool StepPreProcessor::preprocess(const char* path, std::string &output_path)
|
||||
{
|
||||
boost::nowide::ifstream infile(path);
|
||||
if (!infile.good()) {
|
||||
throw Slic3r::RuntimeError(std::string("Load step file failed.\nCannot open file for reading.\n"));
|
||||
throw Slic3r::RuntimeError(_u8L("Load step file failed.\nCannot open file for reading.\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -116,7 +117,7 @@ bool StepPreProcessor::isUtf8File(const char* path)
|
||||
{
|
||||
boost::nowide::ifstream infile(path);
|
||||
if (!infile.good()) {
|
||||
throw Slic3r::RuntimeError(std::string("Load step file failed.\nCannot open file for reading.\n"));
|
||||
throw Slic3r::RuntimeError(_u8L("Load step file failed.\nCannot open file for reading.\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../libslic3r.h"
|
||||
#include "../Model.hpp"
|
||||
#include "../TriangleMesh.hpp"
|
||||
#include "../I18N.hpp"
|
||||
|
||||
#include "svg.hpp"
|
||||
#include "nanosvg/nanosvg.h"
|
||||
@@ -143,11 +144,11 @@ bool get_svg_profile(const char *path, std::vector<Element_Info> &element_infos,
|
||||
NSVGimage *svg_data = nullptr;
|
||||
svg_data = nsvgParseFromFile(path, "mm", 96.0f);
|
||||
if (svg_data == nullptr) {
|
||||
message = "import svg failed: could not open svg.";
|
||||
message = _u8L("import svg failed: could not open svg.");
|
||||
return false;
|
||||
}
|
||||
if (svg_data->shapes == nullptr) {
|
||||
message = "import svg failed: could not parse imported svg data.";
|
||||
message = _u8L("import svg failed: could not parse imported svg data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+13
-9
@@ -1979,7 +1979,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
|
||||
if (m_layer_idx < (int) m_tool_changes.size()) {
|
||||
if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
|
||||
throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
|
||||
throw Slic3r::RuntimeError(_(L("Wipe tower generation failed, possibly due to empty first layer.")));
|
||||
|
||||
// Calculate where the wipe tower layer will be printed. -1 means that print z will not change,
|
||||
// resulting in a wipe tower with sparse layers.
|
||||
@@ -2018,7 +2018,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
|
||||
if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
|
||||
if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
|
||||
throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
|
||||
throw Slic3r::RuntimeError(_(L("Wipe tower generation failed, possibly due to empty first layer.")));
|
||||
|
||||
if (!ignore_sparse)
|
||||
gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z);
|
||||
@@ -2044,7 +2044,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
|
||||
if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
|
||||
if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
|
||||
throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
|
||||
throw Slic3r::RuntimeError(_(L("Wipe tower generation failed, possibly due to empty first layer.")));
|
||||
|
||||
if (!ignore_sparse) {
|
||||
return false;
|
||||
@@ -2792,11 +2792,13 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
m_processor.set_print(print);
|
||||
GCodeOutputStream file(boost::nowide::fopen(path_tmp.c_str(), "wb"), m_processor);
|
||||
if (! file.is_open()) {
|
||||
std::string err_msg = std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n";
|
||||
// TRN %1% is a file path.
|
||||
std::string err_msg = Slic3r::format(_(L("G-code export to %1% failed.\nCannot open the file for writing.")), path) + "\n";
|
||||
BOOST_LOG_TRIVIAL(error) << err_msg << std::endl;
|
||||
if (!fs::exists(folder)) {
|
||||
//fs::create_directory(folder);
|
||||
std::string add_err_msg = "the parent path " + folder.string() +" is not there!!!";
|
||||
// TRN %1% is a folder path.
|
||||
std::string add_err_msg = Slic3r::format(_(L("The folder %1% does not exist.")), folder.string());
|
||||
BOOST_LOG_TRIVIAL(error) << add_err_msg << std::endl;
|
||||
err_msg += add_err_msg;
|
||||
}
|
||||
@@ -2818,7 +2820,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
if (file.is_error()) {
|
||||
file.close();
|
||||
boost::nowide::remove(path_tmp.c_str());
|
||||
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
|
||||
// TRN %1% is a file path.
|
||||
throw Slic3r::RuntimeError(Slic3r::format(_(L("G-code export to %1% failed.\nIs the disk full?")), path) + "\n");
|
||||
}
|
||||
} catch (std::exception &ex) {
|
||||
// Rethrow on any exception. std::runtime_exception and CanceledException are expected to be thrown.
|
||||
@@ -2949,8 +2952,9 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx);
|
||||
}
|
||||
throw Slic3r::RuntimeError(
|
||||
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' + "error code " + ret.message() + '\n' +
|
||||
"Is " + path_tmp + " locked?" + '\n');
|
||||
// TRN %1% is the temporary file path, %2% the output file path, %3% the system error message.
|
||||
Slic3r::format(_(L("Failed to rename the output G-code file from %1% to %2%.\nError: %3%\nIs %1% locked?")),
|
||||
path_tmp, path, ret.message()) + '\n');
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("rename_file from %1% to %2% successfully")% path_tmp % path;
|
||||
@@ -4161,7 +4165,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
auto [thumbnails, errors] = GCodeThumbnails::make_and_check_thumbnail_list(print.full_print_config());
|
||||
|
||||
if (errors != enum_bitmask<ThumbnailError>()) {
|
||||
std::string error_str = format("Invalid thumbnails value:");
|
||||
std::string error_str = _(L("Invalid thumbnails value:"));
|
||||
error_str += GCodeThumbnails::get_error_string(errors);
|
||||
throw Slic3r::ExportError(error_str);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/GCodeWriter.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/I18N.hpp"
|
||||
#include "libslic3r/format.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -321,8 +323,7 @@ std::string AdaptivePAProcessor::validate_adaptive_pa_model(const std::string& m
|
||||
// Only numbers, commas and dots are allowed (no letters or other characters)
|
||||
for (char c : line) {
|
||||
if (!std::isdigit(static_cast<unsigned char>(c)) && c != ',' && c != '.') {
|
||||
return "Line " + std::to_string(line_number) +
|
||||
": only numbers, commas and dots are allowed";
|
||||
return Slic3r::format(_u8L("Line %1%: only numbers, commas and dots are allowed"), line_number);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,8 +334,7 @@ std::string AdaptivePAProcessor::validate_adaptive_pa_model(const std::string& m
|
||||
}
|
||||
|
||||
if (comma_count != 2) {
|
||||
return "Line " + std::to_string(line_number) +
|
||||
": must contain exactly 3 comma-separated values (PA, flow, acceleration)";
|
||||
return Slic3r::format(_u8L("Line %1%: must contain exactly 3 comma-separated values (PA, flow, acceleration)"), line_number);
|
||||
}
|
||||
|
||||
// Parse and validate the values
|
||||
@@ -344,31 +344,31 @@ std::string AdaptivePAProcessor::validate_adaptive_pa_model(const std::string& m
|
||||
|
||||
// Parse PA
|
||||
if (!std::getline(line_stream, value, ','))
|
||||
return "Line " + std::to_string(line_number) + ": missing PA value";
|
||||
return Slic3r::format(_u8L("Line %1%: missing PA value"), line_number);
|
||||
double pa = std::stod(value);
|
||||
|
||||
// Parse flow
|
||||
if (!std::getline(line_stream, value, ','))
|
||||
return "Line " + std::to_string(line_number) + ": missing flow value";
|
||||
return Slic3r::format(_u8L("Line %1%: missing flow value"), line_number);
|
||||
double flow = std::stod(value);
|
||||
|
||||
// Parse acceleration
|
||||
if (!std::getline(line_stream, value, ','))
|
||||
return "Line " + std::to_string(line_number) + ": missing acceleration value";
|
||||
return Slic3r::format(_u8L("Line %1%: missing acceleration value"), line_number);
|
||||
double accel = std::stod(value);
|
||||
|
||||
// Validate constraints
|
||||
if (pa >= 2.0) {
|
||||
return "Line " + std::to_string(line_number) + ": PA value must be less than 2";
|
||||
return Slic3r::format(_u8L("Line %1%: PA value must be less than 2"), line_number);
|
||||
}
|
||||
if (flow <= pa) {
|
||||
return "Line " + std::to_string(line_number) + ": flow value must be greater than PA value";
|
||||
return Slic3r::format(_u8L("Line %1%: flow value must be greater than PA value"), line_number);
|
||||
}
|
||||
if (accel <= flow) {
|
||||
return "Line " + std::to_string(line_number) + ": acceleration value must be greater than flow value";
|
||||
return Slic3r::format(_u8L("Line %1%: acceleration value must be greater than flow value"), line_number);
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
return "Line " + std::to_string(line_number) + ": invalid numeric value";
|
||||
return Slic3r::format(_u8L("Line %1%: invalid numeric value"), line_number);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/LocalesUtils.hpp"
|
||||
#include "libslic3r/format.hpp"
|
||||
#include "libslic3r/I18N.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
#include "GCodeProcessor.hpp"
|
||||
|
||||
@@ -1066,13 +1067,13 @@ void GCodeProcessor::run_post_process()
|
||||
{
|
||||
FilePtr in{ boost::nowide::fopen(m_result.filename.c_str(), "rb") };
|
||||
if (in.f == nullptr)
|
||||
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nCannot open file for reading.\n"));
|
||||
throw Slic3r::RuntimeError(_u8L("G-code processor post-process export failed.\nCannot open file for reading.\n"));
|
||||
|
||||
// temporary file to contain modified gcode
|
||||
std::string out_path = m_result.filename + ".postprocess";
|
||||
FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") };
|
||||
if (out.f == nullptr)
|
||||
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nCannot open file for writing.\n"));
|
||||
throw Slic3r::RuntimeError(_u8L("G-code processor post-process export failed.\nCannot open file for writing.\n"));
|
||||
|
||||
std::vector<double> filament_mm(m_result.filaments_count, 0.0);
|
||||
std::vector<double> filament_cm3(m_result.filaments_count, 0.0);
|
||||
@@ -1467,10 +1468,10 @@ void GCodeProcessor::run_post_process()
|
||||
// found an invalid value, clamp it to a valid one
|
||||
tool_number = std::clamp<int>(0, m_filament_nozzle_temp.size() - 1, tool_number);
|
||||
// emit warning
|
||||
std::string warning = "GCode Post-Processor encountered an invalid toolchange, maybe from a custom gcode:";
|
||||
std::string warning = _u8L("The G-code post-processor encountered an invalid tool change, maybe from custom G-code:");
|
||||
warning += "\n> ";
|
||||
warning += gcode_line;
|
||||
warning += "Generated M104 lines may be incorrect.";
|
||||
warning += _u8L("Generated M104 lines may be incorrect.");
|
||||
BOOST_LOG_TRIVIAL(error) << warning;
|
||||
// Orca todo
|
||||
if (m_print != nullptr)
|
||||
@@ -1712,7 +1713,7 @@ void GCodeProcessor::run_post_process()
|
||||
for (;;) {
|
||||
size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f);
|
||||
if (::ferror(in.f))
|
||||
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nError while reading from file.\n"));
|
||||
throw Slic3r::RuntimeError(_u8L("G-code processor post-process export failed.\nError while reading from file.\n"));
|
||||
bool eof = cnt_read == 0;
|
||||
auto it = buffer.begin();
|
||||
auto it_bufend = buffer.begin() + cnt_read;
|
||||
@@ -1877,8 +1878,9 @@ void GCodeProcessor::run_post_process()
|
||||
}
|
||||
|
||||
if (rename_file(out_path, result_filename))
|
||||
throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + result_filename + '\n' +
|
||||
"Is " + out_path + " locked?" + '\n');
|
||||
// TRN %1% is the temporary file path, %2% the output file path.
|
||||
throw Slic3r::RuntimeError(Slic3r::format(_u8L("Failed to rename the output G-code file from %1% to %2%.\nIs %1% locked?"),
|
||||
out_path, result_filename) + '\n');
|
||||
}
|
||||
|
||||
// Additive second file-rewrite pass for the pre-heat/pre-cool injector. The single-pass
|
||||
@@ -1979,12 +1981,12 @@ void GCodeProcessor::run_second_pass_injection()
|
||||
|
||||
FilePtr in{ boost::nowide::fopen(m_result.filename.c_str(), "rb") };
|
||||
if (in.f == nullptr)
|
||||
throw Slic3r::RuntimeError(std::string("GCode processor pre-heat injection pass failed.\nCannot open file for reading.\n"));
|
||||
throw Slic3r::RuntimeError(_u8L("G-code processor pre-heat injection pass failed.\nCannot open file for reading.\n"));
|
||||
|
||||
const std::string out_path = m_result.filename + ".preheat";
|
||||
FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") };
|
||||
if (out.f == nullptr)
|
||||
throw Slic3r::RuntimeError(std::string("GCode processor pre-heat injection pass failed.\nCannot open file for writing.\n"));
|
||||
throw Slic3r::RuntimeError(_u8L("G-code processor pre-heat injection pass failed.\nCannot open file for writing.\n"));
|
||||
|
||||
// The rewrite may shift byte positions (once the injector inserts lines), so rebuild lines_ends from scratch.
|
||||
// With an empty map the scanned '\n' offsets reproduce the current lines_ends exactly.
|
||||
@@ -2002,7 +2004,7 @@ void GCodeProcessor::run_second_pass_injection()
|
||||
for (;;) {
|
||||
size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f);
|
||||
if (::ferror(in.f))
|
||||
throw Slic3r::RuntimeError(std::string("GCode processor pre-heat injection pass failed.\nError while reading from file.\n"));
|
||||
throw Slic3r::RuntimeError(_u8L("G-code processor pre-heat injection pass failed.\nError while reading from file.\n"));
|
||||
bool eof = cnt_read == 0;
|
||||
auto it = buffer.begin();
|
||||
auto it_bufend = buffer.begin() + cnt_read;
|
||||
@@ -2053,8 +2055,9 @@ void GCodeProcessor::run_second_pass_injection()
|
||||
handle_offsets_of_second_process(inserted_operation_lines);
|
||||
|
||||
if (rename_file(out_path, m_result.filename))
|
||||
throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + m_result.filename + '\n' +
|
||||
"Is " + out_path + " locked?" + '\n');
|
||||
// TRN %1% is the temporary file path, %2% the output file path.
|
||||
throw Slic3r::RuntimeError(Slic3r::format(_u8L("Failed to rename the output G-code file from %1% to %2%.\nIs %1% locked?"),
|
||||
out_path, m_result.filename) + '\n');
|
||||
}
|
||||
|
||||
// Every move whose gcode_id sits at or after an inserted line is pushed down by the running count of
|
||||
@@ -3941,7 +3944,7 @@ ConfigSubstitutions load_from_superslicer_gcode_file(const std::string& filename
|
||||
key_value_pairs = ConfigBase::load_from_gcode_string_legacy(config, data.data(), substitutions_ctxt);
|
||||
|
||||
if (key_value_pairs < 80)
|
||||
throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", filename, key_value_pairs));
|
||||
throw Slic3r::RuntimeError(format(_u8L("Suspiciously low number of configuration values extracted from %1%: %2%"), filename, key_value_pairs));
|
||||
|
||||
return std::move(substitutions_ctxt.substitutions);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "libslic3r/Exception.hpp"
|
||||
#include "libslic3r/GCode/PchipInterpolatorHelper.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/I18N.hpp"
|
||||
#include "libslic3r/format.hpp"
|
||||
|
||||
#include "SmallAreaInfillFlowCompensator.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
@@ -55,10 +57,8 @@ SmallAreaInfillFlowCompensator::SmallAreaInfillFlowCompensator(const Slic3r::GCo
|
||||
flowComps.push_back(std::stod(value_str));
|
||||
}
|
||||
} catch (...) {
|
||||
std::stringstream ss;
|
||||
ss << "Small Area Flow Compensation: Error parsing data point in small area infill compensation model:" << line << std::endl;
|
||||
|
||||
throw Slic3r::InvalidArgument(ss.str());
|
||||
// TRN %1% is the line of the model that could not be parsed.
|
||||
throw Slic3r::InvalidArgument(Slic3r::format(_u8L("Small Area Flow Compensation: Error parsing data point in small area infill compensation model: %1%"), line) + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,26 +66,26 @@ SmallAreaInfillFlowCompensator::SmallAreaInfillFlowCompensator(const Slic3r::GCo
|
||||
for (size_t i = 0; i < eLengths.size(); i++) {
|
||||
if (i == 0) {
|
||||
if (!nearly_equal(eLengths[i], 0.0)) {
|
||||
throw Slic3r::InvalidArgument("Small Area Flow Compensation: First extrusion length for small area infill compensation model must be 0");
|
||||
throw Slic3r::InvalidArgument(_u8L("Small Area Flow Compensation: First extrusion length for small area infill compensation model must be 0"));
|
||||
}
|
||||
} else {
|
||||
if (nearly_equal(eLengths[i], 0.0)) {
|
||||
throw Slic3r::InvalidArgument("Small Area Flow Compensation: Only the first extrusion length for small area infill compensation model can be 0");
|
||||
throw Slic3r::InvalidArgument(_u8L("Small Area Flow Compensation: Only the first extrusion length for small area infill compensation model can be 0"));
|
||||
}
|
||||
if (eLengths[i] <= eLengths[i - 1]) {
|
||||
throw Slic3r::InvalidArgument("Small Area Flow Compensation: Extrusion lengths for subsequent points must be increasing");
|
||||
throw Slic3r::InvalidArgument(_u8L("Small Area Flow Compensation: Extrusion lengths for subsequent points must be increasing"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < flowComps.size(); ++i) {
|
||||
if (flowComps[i] <= flowComps[i - 1]) {
|
||||
throw Slic3r::InvalidArgument("Small Area Flow Compensation: Flow compensation factors must strictly increase with extrusion length");
|
||||
throw Slic3r::InvalidArgument(_u8L("Small Area Flow Compensation: Flow compensation factors must strictly increase with extrusion length"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!flowComps.empty() && !nearly_equal(flowComps.back(), 1.0)) {
|
||||
throw Slic3r::InvalidArgument("Small Area Flow Compensation: Final compensation factor for small area infill flow compensation model must be 1.0");
|
||||
throw Slic3r::InvalidArgument(_u8L("Small Area Flow Compensation: Final compensation factor for small area infill flow compensation model must be 1.0"));
|
||||
}
|
||||
|
||||
flowModel = std::make_unique<PchipInterpolatorHelper>(eLengths, flowComps);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/enum_bitmask.hpp"
|
||||
#include "format.hpp"
|
||||
#include "libslic3r/I18N.hpp"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <qoi/qoi.h>
|
||||
@@ -610,11 +611,11 @@ std::string get_error_string(const ThumbnailErrors& errors)
|
||||
std::string error_str;
|
||||
|
||||
if (errors.has(ThumbnailError::InvalidVal))
|
||||
error_str += "\n - " + Slic3r::format("Invalid input format. Expected vector of dimensions in the following format: \"%1%\"", "XxY/EXT, XxY/EXT, ...");
|
||||
error_str += "\n - " + Slic3r::format(_u8L("Invalid input format. Expected vector of dimensions in the following format: \"%1%\""), "XxY/EXT, XxY/EXT, ...");
|
||||
if (errors.has(ThumbnailError::OutOfRange))
|
||||
error_str += "\n - Input value is out of range";
|
||||
error_str += "\n - " + _u8L("Input value is out of range");
|
||||
if (errors.has(ThumbnailError::InvalidExt))
|
||||
error_str += "\n - Some extension in the input is invalid";
|
||||
error_str += "\n - " + _u8L("Some extension in the input is invalid");
|
||||
|
||||
return error_str;
|
||||
}
|
||||
|
||||
@@ -1646,7 +1646,7 @@ static FilamentGroupContext build_filament_group_context(
|
||||
context.nozzle_info.extruder_nozzle_list = build_extruder_nozzle_list(context.nozzle_info.nozzle_list);
|
||||
|
||||
if (context.nozzle_info.nozzle_list.empty())
|
||||
throw Slic3r::RuntimeError("No valid nozzle found. Please check nozzle count.");
|
||||
throw Slic3r::RuntimeError(_L("No valid nozzle found. Please check nozzle count."));
|
||||
|
||||
if (!nozzle_status.empty())
|
||||
context.nozzle_info.nozzle_status = nozzle_status;
|
||||
|
||||
@@ -198,10 +198,12 @@ std::string imex_multicolor_block_reason(const std::string& parallel_mode,
|
||||
// Filaments are numbered from 1 as the sidebar shows them, heads by their T index; the map
|
||||
// decides which head a filament is on, so with MMU lanes the two numbers differ.
|
||||
if (phys < 0)
|
||||
return (boost::format(L("In this Span mode only %1% print colors, but filament %2% isn't routed to any "
|
||||
// TRN %1% is a list of tools such as "T0/T1", %2% a filament number.
|
||||
return (boost::format(L("In this Span mode, colors are printed only by %1%, but filament %2% isn't routed to any "
|
||||
"tool. Use filaments routed to %1%, or switch this plate to Primary mode.")) %
|
||||
tools % (filament + 1)).str();
|
||||
return (boost::format(L("In this Span mode only %1% print colors, but filament %2% is routed to T%3%. Use "
|
||||
// TRN %1% is a list of tools such as "T0/T1", %2% a filament number, %3% a tool number.
|
||||
return (boost::format(L("In this Span mode, colors are printed only by %1%, but filament %2% is routed to T%3%. Use "
|
||||
"filaments routed to %1%, or switch this plate to Primary mode.")) %
|
||||
tools % (filament + 1) % phys).str();
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ Model Model::read_from_file(const std::string&
|
||||
boost::algorithm::iends_with(input_file, ".abc") || boost::algorithm::iends_with(input_file, ".ply")) {
|
||||
std::string temp_stl = make_temp_stl_with_modelio(input_file);
|
||||
if (temp_stl.empty()) {
|
||||
throw Slic3r::RuntimeError("Failed to convert asset to STL via ModelIO.");
|
||||
throw Slic3r::RuntimeError(_L("Failed to convert asset to STL via ModelIO."));
|
||||
}
|
||||
result = load_stl(temp_stl.c_str(), &model);
|
||||
delete_temp_file(temp_stl);
|
||||
|
||||
+133
-132
@@ -5,6 +5,8 @@
|
||||
#include "PrintConfig.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "format.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
#include <cassert>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
@@ -383,7 +385,7 @@ namespace client
|
||||
case TYPE_DOUBLE:
|
||||
return expr(- this->d(), start_pos, this->it_range.end());
|
||||
default:
|
||||
this->throw_exception("Cannot apply unary minus operator.");
|
||||
this->throw_exception(L("Cannot apply unary minus operator."));
|
||||
}
|
||||
assert(false);
|
||||
// Suppress compiler warnings.
|
||||
@@ -401,7 +403,7 @@ namespace client
|
||||
case TYPE_DOUBLE:
|
||||
return expr(static_cast<int>(this->d()), start_pos, this->it_range.end());
|
||||
default:
|
||||
this->throw_exception("Cannot convert to integer.");
|
||||
this->throw_exception(L("Cannot convert to integer."));
|
||||
}
|
||||
assert(false);
|
||||
// Suppress compiler warnings.
|
||||
@@ -419,7 +421,7 @@ namespace client
|
||||
case TYPE_DOUBLE:
|
||||
return expr(static_cast<int>(std::round(this->d())), start_pos, this->it_range.end());
|
||||
default:
|
||||
this->throw_exception("Cannot round a non-numeric value.");
|
||||
this->throw_exception(L("Cannot round a non-numeric value."));
|
||||
}
|
||||
assert(false);
|
||||
// Suppress compiler warnings.
|
||||
@@ -434,7 +436,7 @@ namespace client
|
||||
case TYPE_DOUBLE:
|
||||
return expr(static_cast<int>(std::floor(this->d())), start_pos, this->it_range.end());
|
||||
default:
|
||||
this->throw_exception("Cannot floor a non-numeric value.");
|
||||
this->throw_exception(L("Cannot floor a non-numeric value."));
|
||||
}
|
||||
assert(false);
|
||||
// Suppress compiler warnings.
|
||||
@@ -449,7 +451,7 @@ namespace client
|
||||
case TYPE_DOUBLE:
|
||||
return expr(static_cast<int>(std::ceil(this->d())), start_pos, this->it_range.end());
|
||||
default:
|
||||
this->throw_exception("Cannot ceil a non-numeric value.");
|
||||
this->throw_exception(L("Cannot ceil a non-numeric value."));
|
||||
}
|
||||
assert(false);
|
||||
// Suppress compiler warnings.
|
||||
@@ -465,7 +467,7 @@ namespace client
|
||||
case TYPE_BOOL:
|
||||
return expr(! this->b(), start_pos, this->it_range.end());
|
||||
default:
|
||||
this->throw_exception("Cannot apply a not operator.");
|
||||
this->throw_exception(L("Cannot apply a not operator."));
|
||||
}
|
||||
assert(false);
|
||||
// Suppress compiler warnings.
|
||||
@@ -483,7 +485,7 @@ namespace client
|
||||
// Conver the left hand side to string, append rhs.
|
||||
this->set_s(this->to_string() + rhs.s());
|
||||
} else {
|
||||
const char *err_msg = "Cannot add non-numeric types.";
|
||||
const char *err_msg = L("Cannot add non-numeric types.");
|
||||
this->throw_if_not_numeric(err_msg);
|
||||
rhs.throw_if_not_numeric(err_msg);
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
@@ -501,7 +503,7 @@ namespace client
|
||||
// Inside an if / else block to be skipped.
|
||||
this->reset();
|
||||
} else {
|
||||
const char *err_msg = "Cannot subtract non-numeric types.";
|
||||
const char *err_msg = L("Cannot subtract non-numeric types.");
|
||||
this->throw_if_not_numeric(err_msg);
|
||||
rhs.throw_if_not_numeric(err_msg);
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
@@ -519,7 +521,7 @@ namespace client
|
||||
// Inside an if / else block to be skipped.
|
||||
this->reset();
|
||||
} else {
|
||||
const char *err_msg = "Cannot multiply with non-numeric type.";
|
||||
const char *err_msg = L("Cannot multiply with non-numeric type.");
|
||||
this->throw_if_not_numeric(err_msg);
|
||||
rhs.throw_if_not_numeric(err_msg);
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
@@ -537,10 +539,10 @@ namespace client
|
||||
// Inside an if / else block to be skipped.
|
||||
this->reset();
|
||||
} else {
|
||||
this->throw_if_not_numeric("Cannot divide a non-numeric type.");
|
||||
rhs.throw_if_not_numeric("Cannot divide with a non-numeric type.");
|
||||
this->throw_if_not_numeric(L("Cannot divide a non-numeric type."));
|
||||
rhs.throw_if_not_numeric(L("Cannot divide with a non-numeric type."));
|
||||
if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.))
|
||||
rhs.throw_exception("Division by zero");
|
||||
rhs.throw_exception(L("Division by zero"));
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
this->set_d_lite(this->as_d() / rhs.as_d());
|
||||
else
|
||||
@@ -556,10 +558,10 @@ namespace client
|
||||
// Inside an if / else block to be skipped.
|
||||
this->reset();
|
||||
} else {
|
||||
this->throw_if_not_numeric("Cannot divide a non-numeric type.");
|
||||
rhs.throw_if_not_numeric("Cannot divide with a non-numeric type.");
|
||||
this->throw_if_not_numeric(L("Cannot divide a non-numeric type."));
|
||||
rhs.throw_if_not_numeric(L("Cannot divide with a non-numeric type."));
|
||||
if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.))
|
||||
rhs.throw_exception("Division by zero");
|
||||
rhs.throw_exception(L("Division by zero"));
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
this->set_d_lite(std::fmod(this->as_d(), rhs.as_d()));
|
||||
else
|
||||
@@ -581,7 +583,7 @@ namespace client
|
||||
if (self.type() != TYPE_EMPTY) {
|
||||
// Not inside an if / else block to be skipped
|
||||
if (self.type() != TYPE_BOOL)
|
||||
self.throw_exception("Not a boolean expression");
|
||||
self.throw_exception(L("Not a boolean expression"));
|
||||
out = self.b();
|
||||
}
|
||||
}
|
||||
@@ -590,7 +592,7 @@ namespace client
|
||||
{
|
||||
assert(self.type() != TYPE_EMPTY);
|
||||
if (self.type() != TYPE_BOOL)
|
||||
self.throw_exception("Not a boolean expression");
|
||||
self.throw_exception(L("Not a boolean expression"));
|
||||
out = self.b() ? "true" : "false";
|
||||
}
|
||||
|
||||
@@ -622,7 +624,7 @@ namespace client
|
||||
// Both type are bool.
|
||||
if (op != '=')
|
||||
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot compare the types.")));
|
||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info(std::string("*") + L("Cannot compare the types."))));
|
||||
value = lhs.b() == rhs.b();
|
||||
} else if (lhs.type() == TYPE_STRING || rhs.type() == TYPE_STRING) {
|
||||
// One type is string, the other could be converted to string.
|
||||
@@ -630,7 +632,7 @@ namespace client
|
||||
(op == '<') ? (lhs.to_string() < rhs.to_string()) : (lhs.to_string() > rhs.to_string());
|
||||
} else {
|
||||
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot compare the types.")));
|
||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info(std::string("*") + L("Cannot compare the types."))));
|
||||
}
|
||||
lhs.reset();
|
||||
lhs.set_b_lite(invert ? ! value : value);
|
||||
@@ -645,7 +647,7 @@ namespace client
|
||||
|
||||
static void throw_if_not_numeric(const expr ¶m)
|
||||
{
|
||||
const char *err_msg = "Not a numeric type.";
|
||||
const char *err_msg = L("Not a numeric type.");
|
||||
param.throw_if_not_numeric(err_msg);
|
||||
}
|
||||
|
||||
@@ -707,10 +709,10 @@ namespace client
|
||||
return;
|
||||
throw_if_not_numeric(param1);
|
||||
if (param2.type() != TYPE_INT)
|
||||
param2.throw_exception("digits: second parameter must be integer");
|
||||
param2.throw_exception(L("digits: second parameter must be integer"));
|
||||
bool has_decimals = param3.type() != TYPE_EMPTY;
|
||||
if (has_decimals && param3.type() != TYPE_INT)
|
||||
param3.throw_exception("digits: third parameter must be integer");
|
||||
param3.throw_exception(L("digits: third parameter must be integer"));
|
||||
|
||||
char buf[256];
|
||||
int ndigits = std::clamp(param2.as_i(), 0, 64);
|
||||
@@ -734,7 +736,7 @@ namespace client
|
||||
// One type is string, the other could be converted to string.
|
||||
subject = &lhs.s();
|
||||
} else {
|
||||
lhs.throw_exception("Left hand side of a regex match must be a string.");
|
||||
lhs.throw_exception(L("Left hand side of a regex match must be a string."));
|
||||
}
|
||||
try {
|
||||
std::string pattern(++ rhs.begin(), -- rhs.end());
|
||||
@@ -745,7 +747,7 @@ namespace client
|
||||
} catch (SLIC3R_REGEX_NAMESPACE::regex_error &ex) {
|
||||
// Syntax error in the regular expression
|
||||
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||
rhs.begin(), rhs.end(), spirit::info(std::string("*Regular expression compilation failed: ") + ex.what())));
|
||||
rhs.begin(), rhs.end(), spirit::info("*" + Slic3r::format(_u8L("Regular expression compilation failed: %1%"), ex.what()))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -760,7 +762,7 @@ namespace client
|
||||
// Inside an if / else block to be skipped
|
||||
return;
|
||||
if (subject.type() != TYPE_STRING)
|
||||
subject.throw_exception("regex_replace() first parameter must be a string.");
|
||||
subject.throw_exception(L("regex_replace() first parameter must be a string."));
|
||||
try {
|
||||
std::string re(++ pattern.begin(), -- pattern.end());
|
||||
std::string result = SLIC3R_REGEX_NAMESPACE::regex_replace(subject.s(), SLIC3R_REGEX_NAMESPACE::regex(re), replacement.to_string());
|
||||
@@ -768,7 +770,7 @@ namespace client
|
||||
} catch (SLIC3R_REGEX_NAMESPACE::regex_error &ex) {
|
||||
// Syntax error in the regular expression
|
||||
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||
pattern.begin(), pattern.end(), spirit::info(std::string("*Regular expression compilation failed: ") + ex.what())));
|
||||
pattern.begin(), pattern.end(), spirit::info("*" + Slic3r::format(_u8L("Regular expression compilation failed: %1%"), ex.what()))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -784,15 +786,15 @@ namespace client
|
||||
}
|
||||
if (! out.b()) {
|
||||
if (match.type() != TYPE_STRING)
|
||||
match.throw_exception("one_of(): First parameter (the string to match against) has to be a string value");
|
||||
match.throw_exception(L("one_of(): First parameter (the string to match against) has to be a string value"));
|
||||
if (pattern.type() != TYPE_STRING)
|
||||
match.throw_exception("one_of(): Pattern has to be a string value");
|
||||
match.throw_exception(L("one_of(): Pattern has to be a string value"));
|
||||
if (RegEx) {
|
||||
try {
|
||||
out.set_b(SLIC3R_REGEX_NAMESPACE::regex_match(match.s(), SLIC3R_REGEX_NAMESPACE::regex(pattern.s())));
|
||||
} catch (SLIC3R_REGEX_NAMESPACE::regex_error &) {
|
||||
// Syntax error in the regular expression
|
||||
pattern.throw_exception("Regular expression compilation failed");
|
||||
pattern.throw_exception(L("Regular expression compilation failed"));
|
||||
}
|
||||
} else
|
||||
out.set_b(match.s() == pattern.s());
|
||||
@@ -806,7 +808,7 @@ namespace client
|
||||
}
|
||||
if (! out.b()) {
|
||||
if (match.type() != TYPE_STRING)
|
||||
match.throw_exception("one_of(): First parameter (the string to match against) has to be a string value");
|
||||
match.throw_exception(L("one_of(): First parameter (the string to match against) has to be a string value"));
|
||||
regex_op(match, pattern, '=', out);
|
||||
}
|
||||
}
|
||||
@@ -821,7 +823,7 @@ namespace client
|
||||
value = (op == '|') ? (lhs.b() || rhs.b()) : (lhs.b() && rhs.b());
|
||||
} else {
|
||||
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot apply logical operation to non-boolean operators.")));
|
||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info(std::string("*") + L("Cannot apply logical operation to non-boolean operands."))));
|
||||
}
|
||||
lhs.set_b_lite(value);
|
||||
}
|
||||
@@ -984,30 +986,30 @@ namespace client
|
||||
opt = ctx->resolve_symbol(opt_key_str.substr(0, idx));
|
||||
if (opt != nullptr) {
|
||||
if (! opt->is_vector())
|
||||
ctx->throw_exception("Trying to index a scalar variable", opt_key);
|
||||
ctx->throw_exception(L("Trying to index a scalar variable"), opt_key);
|
||||
char *endptr = nullptr;
|
||||
idx = strtol(opt_key_str.c_str() + idx + 1, &endptr, 10);
|
||||
if (endptr == nullptr || *endptr != 0)
|
||||
ctx->throw_exception("Invalid vector index", IteratorRange(opt_key.begin() + idx + 1, opt_key.end()));
|
||||
ctx->throw_exception(L("Invalid vector index"), IteratorRange(opt_key.begin() + idx + 1, opt_key.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opt == nullptr)
|
||||
ctx->throw_exception(ctx->skipping() ? "Variable does not exist (in an inactive branch)" : "Variable does not exist", opt_key);
|
||||
ctx->throw_exception(ctx->skipping() ? L("Variable does not exist (in an inactive branch)") : L("Variable does not exist"), opt_key);
|
||||
if (ctx->skipping())
|
||||
return;
|
||||
if (opt->is_scalar()) {
|
||||
if (opt->is_nil())
|
||||
ctx->throw_exception("Trying to reference an undefined (nil) optional variable", opt_key);
|
||||
ctx->throw_exception(L("Trying to reference an undefined (nil) optional variable"), opt_key);
|
||||
output = opt->serialize();
|
||||
} else {
|
||||
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt);
|
||||
if (vec->empty())
|
||||
ctx->throw_exception("Indexing an empty vector variable", opt_key);
|
||||
ctx->throw_exception(L("Indexing an empty vector variable"), opt_key);
|
||||
if (idx >= vec->size())
|
||||
idx = 0;
|
||||
if (vec->is_nil(idx))
|
||||
ctx->throw_exception("Trying to reference an undefined (nil) element of vector of optional values", opt_key);
|
||||
ctx->throw_exception(L("Trying to reference an undefined (nil) element of vector of optional values"), opt_key);
|
||||
output = vec->vserialize()[idx];
|
||||
}
|
||||
}
|
||||
@@ -1021,7 +1023,7 @@ namespace client
|
||||
if (ctx->skipping() && ! ctx->check_inactive_names())
|
||||
return;
|
||||
|
||||
const char *not_found = ctx->skipping() ? "Variable does not exist (in an inactive branch)" : "Variable does not exist";
|
||||
const char *not_found = ctx->skipping() ? L("Variable does not exist (in an inactive branch)") : L("Variable does not exist");
|
||||
std::string opt_key_str(opt_key.begin(), opt_key.end());
|
||||
const ConfigOption *opt = ctx->resolve_symbol(opt_key_str);
|
||||
if (opt == nullptr) {
|
||||
@@ -1034,24 +1036,24 @@ namespace client
|
||||
ctx->throw_exception(not_found, opt_key);
|
||||
}
|
||||
if (! opt->is_vector())
|
||||
ctx->throw_exception("Trying to index a scalar variable", opt_key);
|
||||
ctx->throw_exception(L("Trying to index a scalar variable"), opt_key);
|
||||
const ConfigOption *opt_index = ctx->resolve_symbol(std::string(opt_vector_index.begin(), opt_vector_index.end()));
|
||||
if (opt_index == nullptr)
|
||||
ctx->throw_exception(not_found, opt_key);
|
||||
if (opt_index->type() != coInt)
|
||||
ctx->throw_exception("Indexing variable has to be integer", opt_key);
|
||||
ctx->throw_exception(L("Indexing variable has to be integer"), opt_key);
|
||||
if (ctx->skipping())
|
||||
return;
|
||||
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt);
|
||||
if (vec->empty())
|
||||
ctx->throw_exception("Indexing an empty vector variable", opt_key);
|
||||
ctx->throw_exception(L("Indexing an empty vector variable"), opt_key);
|
||||
int idx = opt_index->getInt();
|
||||
if (idx < 0)
|
||||
ctx->throw_exception("Negative vector index", opt_key);
|
||||
ctx->throw_exception(L("Negative vector index"), opt_key);
|
||||
if (idx >= (int)vec->size())
|
||||
idx = 0;
|
||||
if (vec->is_nil(idx))
|
||||
ctx->throw_exception("Trying to reference an undefined (nil) element of vector of optional values", opt_key);
|
||||
ctx->throw_exception(L("Trying to reference an undefined (nil) element of vector of optional values"), opt_key);
|
||||
output = vec->vserialize()[idx];
|
||||
}
|
||||
|
||||
@@ -1066,7 +1068,7 @@ namespace client
|
||||
if (opt == nullptr) {
|
||||
opt = ctx->resolve_output_symbol(key);
|
||||
if (opt == nullptr)
|
||||
ctx->throw_exception("Not a variable name", opt_key);
|
||||
ctx->throw_exception(L("Not a variable name"), opt_key);
|
||||
output.writable = true;
|
||||
}
|
||||
output.opt = opt;
|
||||
@@ -1076,7 +1078,7 @@ namespace client
|
||||
if (ctx->resolve_symbol(key) == nullptr && ctx->resolve_output_symbol(key) == nullptr &&
|
||||
ctx->inactive_local_variables.count(key) == 0 &&
|
||||
(ctx->context_data == nullptr || ctx->context_data->inactive_global_variables.count(key) == 0))
|
||||
ctx->throw_exception("Not a variable name (in an inactive branch)", opt_key);
|
||||
ctx->throw_exception(L("Not a variable name (in an inactive branch)"), opt_key);
|
||||
}
|
||||
output.it_range = opt_key;
|
||||
}
|
||||
@@ -1110,7 +1112,7 @@ namespace client
|
||||
assert(opt.opt->is_scalar());
|
||||
|
||||
if (opt.opt->is_nil())
|
||||
ctx->throw_exception("Trying to reference an undefined (nil) optional variable", opt.it_range);
|
||||
ctx->throw_exception(L("Trying to reference an undefined (nil) optional variable"), opt.it_range);
|
||||
|
||||
switch (opt.opt->type()) {
|
||||
case coFloat: output.set_d(opt.opt->getFloat()); break;
|
||||
@@ -1137,7 +1139,7 @@ namespace client
|
||||
for (;;) {
|
||||
const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over);
|
||||
if (opt_parent == nullptr)
|
||||
ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range);
|
||||
ctx->throw_exception(L("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies"), opt.it_range);
|
||||
if (boost::ends_with(opt_def->ratio_over, "line_width")) {
|
||||
// Line width supports defaults and a complex graph of dependencies.
|
||||
assert(opt_parent->type() == coFloatOrPercent);
|
||||
@@ -1159,7 +1161,7 @@ namespace client
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ctx->throw_exception("Unsupported scalar variable type", opt.it_range);
|
||||
ctx->throw_exception(L("Unsupported scalar variable type"), opt.it_range);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1173,7 +1175,7 @@ namespace client
|
||||
assert(opt.opt->is_vector());
|
||||
const ConfigOptionVectorBase* vec = static_cast<const ConfigOptionVectorBase*>(opt.opt);
|
||||
if (vec->empty())
|
||||
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
|
||||
ctx->throw_exception(L("Indexing an empty vector variable"), opt.it_range);
|
||||
|
||||
// Helper to resolve a FloatOrPercent value (handles ratio_over chain for percent values).
|
||||
// elem_index: the element index used to access this vector element, so that
|
||||
@@ -1194,7 +1196,7 @@ namespace client
|
||||
for (;;) {
|
||||
const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over);
|
||||
if (opt_parent == nullptr)
|
||||
ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range);
|
||||
ctx->throw_exception(L("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies"), opt.it_range);
|
||||
if (boost::ends_with(opt_def->ratio_over, "line_width")) {
|
||||
// Line width supports defaults and a complex graph of dependencies.
|
||||
assert(opt_parent->type() == coFloatOrPercent);
|
||||
@@ -1277,12 +1279,12 @@ namespace client
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
|
||||
default: ctx->throw_exception(L("Referencing a vector variable when scalar is expected"), opt.it_range);
|
||||
}
|
||||
} else {
|
||||
size_t idx = (opt.index < 0) ? 0 : (opt.index >= int(vec->size())) ? 0 : size_t(opt.index);
|
||||
if (vec->is_nil(idx))
|
||||
ctx->throw_exception("Trying to reference an undefined (nil) element of vector of optional values", opt.it_range);
|
||||
ctx->throw_exception(L("Trying to reference an undefined (nil) element of vector of optional values"), opt.it_range);
|
||||
switch (opt.opt->type()) {
|
||||
case coFloats: output.set_d(static_cast<const ConfigOptionFloats*>(opt.opt)->values[idx]); break;
|
||||
case coInts: output.set_i(static_cast<const ConfigOptionInts*>(opt.opt)->values[idx]); break;
|
||||
@@ -1301,27 +1303,27 @@ namespace client
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ctx->throw_exception("Unsupported vector variable type", opt.it_range);
|
||||
ctx->throw_exception(L("Unsupported vector variable type"), opt.it_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_writable(const MyContext *ctx, OptWithPos &opt) {
|
||||
if (! opt.writable)
|
||||
ctx->throw_exception("Cannot modify a read-only variable", opt.it_range);
|
||||
ctx->throw_exception(L("Cannot modify a read-only variable"), opt.it_range);
|
||||
}
|
||||
|
||||
static void check_numeric(const expr ¶m) {
|
||||
if (! param.numeric_type())
|
||||
param.throw_exception("Right side is not a numeric expression");
|
||||
param.throw_exception(L("Right side is not a numeric expression"));
|
||||
};
|
||||
|
||||
static size_t evaluate_count(const expr &expr_count) {
|
||||
if (expr_count.type() != expr::TYPE_INT)
|
||||
expr_count.throw_exception("Expected number of elements to fill a vector with.");
|
||||
expr_count.throw_exception(L("Expected number of elements to fill a vector with."));
|
||||
int count = expr_count.i();
|
||||
if (count < 0)
|
||||
expr_count.throw_exception("Negative number of elements specified.");
|
||||
expr_count.throw_exception(L("Negative number of elements specified."));
|
||||
return size_t(count);
|
||||
};
|
||||
|
||||
@@ -1349,11 +1351,11 @@ namespace client
|
||||
break;
|
||||
case coBool:
|
||||
if (rhs.type() != expr::TYPE_BOOL)
|
||||
ctx->throw_exception("Right side is not a boolean expression", rhs.it_range);
|
||||
ctx->throw_exception(L("Right side is not a boolean expression"), rhs.it_range);
|
||||
static_cast<ConfigOptionBool*>(wropt)->value = rhs.b();
|
||||
break;
|
||||
default:
|
||||
ctx->throw_exception("Unsupported output scalar variable type", lhs.it_range);
|
||||
ctx->throw_exception(L("Unsupported output scalar variable type"), lhs.it_range);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1363,12 +1365,12 @@ namespace client
|
||||
assert(lhs.opt->is_vector());
|
||||
check_writable(ctx, lhs);
|
||||
if (! lhs.has_index())
|
||||
ctx->throw_exception("Referencing an output vector variable when scalar is expected", lhs.it_range);
|
||||
ctx->throw_exception(L("Referencing an output vector variable when scalar is expected"), lhs.it_range);
|
||||
ConfigOptionVectorBase *vec = const_cast<ConfigOptionVectorBase*>(static_cast<const ConfigOptionVectorBase*>(lhs.opt));
|
||||
if (vec->empty())
|
||||
ctx->throw_exception("Indexing an empty vector variable", lhs.it_range);
|
||||
ctx->throw_exception(L("Indexing an empty vector variable"), lhs.it_range);
|
||||
if (lhs.index >= int(vec->size()))
|
||||
ctx->throw_exception("Index out of range", lhs.it_range);
|
||||
ctx->throw_exception(L("Index out of range"), lhs.it_range);
|
||||
switch (lhs.opt->type()) {
|
||||
case coFloats:
|
||||
check_numeric(rhs);
|
||||
@@ -1387,11 +1389,11 @@ namespace client
|
||||
break;
|
||||
case coBools:
|
||||
if (rhs.type() != expr::TYPE_BOOL)
|
||||
ctx->throw_exception("Right side is not a boolean expression", rhs.it_range);
|
||||
ctx->throw_exception(L("Right side is not a boolean expression"), rhs.it_range);
|
||||
static_cast<ConfigOptionBools*>(vec)->values[lhs.index] = rhs.b();
|
||||
break;
|
||||
default:
|
||||
ctx->throw_exception("Unsupported output vector variable type", lhs.it_range);
|
||||
ctx->throw_exception(L("Unsupported output vector variable type"), lhs.it_range);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1414,7 +1416,7 @@ namespace client
|
||||
break;
|
||||
case coBools:
|
||||
if (rhs_value.type() != expr::TYPE_BOOL)
|
||||
rhs_value.throw_exception("Right side is not a boolean expression");
|
||||
rhs_value.throw_exception(L("Right side is not a boolean expression"));
|
||||
static_cast<ConfigOptionBools*>(opt)->values.assign(count, rhs_value.b());
|
||||
break;
|
||||
default: assert(false);
|
||||
@@ -1439,10 +1441,10 @@ namespace client
|
||||
if (ctx->skipping()) {
|
||||
} else if (opt.opt->is_vector()) {
|
||||
if (! opt.has_index())
|
||||
ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
|
||||
ctx->throw_exception(L("Referencing a vector variable when scalar is expected"), opt.it_range);
|
||||
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt.opt);
|
||||
if (vec->empty())
|
||||
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
|
||||
ctx->throw_exception(L("Indexing an empty vector variable"), opt.it_range);
|
||||
output.set_b(static_cast<const ConfigOptionVectorBase*>(opt.opt)->is_nil(opt.index >= int(vec->size()) ? 0 : size_t(opt.index)));
|
||||
} else {
|
||||
assert(opt.opt->is_scalar());
|
||||
@@ -1466,19 +1468,19 @@ namespace client
|
||||
if (! ctx->skipping()) {
|
||||
t_config_option_key key(std::string(it_range.begin(), it_range.end()));
|
||||
if (const ConfigOption* opt = ctx->resolve_symbol(key); opt)
|
||||
ctx->throw_exception("Symbol is already defined in read-only system dictionary", it_range);
|
||||
ctx->throw_exception(L("Symbol is already defined in read-only system dictionary"), it_range);
|
||||
if (ctx->config_outputs && ctx->config_outputs->optptr(key))
|
||||
ctx->throw_exception("Symbol is already defined as system output variable", it_range);
|
||||
ctx->throw_exception(L("Symbol is already defined as system output variable"), it_range);
|
||||
bool has_global_dictionary = ctx->context_data != nullptr && ctx->context_data->global_config;
|
||||
if (global_variable) {
|
||||
if (! has_global_dictionary)
|
||||
ctx->throw_exception("Global variables are not available in this context", it_range);
|
||||
ctx->throw_exception(L("Global variables are not available in this context"), it_range);
|
||||
if (ctx->config_local.optptr(key))
|
||||
ctx->throw_exception("Variable name already defined in local scope", it_range);
|
||||
ctx->throw_exception(L("Variable name already defined in local scope"), it_range);
|
||||
out.opt = ctx->context_data->global_config->optptr(key);
|
||||
} else {
|
||||
if (has_global_dictionary && ctx->context_data->global_config->optptr(key))
|
||||
ctx->throw_exception("Variable name already defined in global scope", it_range);
|
||||
ctx->throw_exception(L("Variable name already defined in global scope"), it_range);
|
||||
out.opt = ctx->config_local.optptr(key);
|
||||
}
|
||||
out.name = std::move(key);
|
||||
@@ -1514,7 +1516,7 @@ namespace client
|
||||
if (ctx->skipping()) {
|
||||
} else if (lhs.opt) {
|
||||
if (lhs.opt->is_vector())
|
||||
rhs.throw_exception("Cannot assign a scalar value to a vector variable.");
|
||||
rhs.throw_exception(L("Cannot assign a scalar value to a vector variable."));
|
||||
OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true };
|
||||
scalar_variable_assign_scalar(ctx, lhs_opt, rhs);
|
||||
} else {
|
||||
@@ -1540,7 +1542,7 @@ namespace client
|
||||
if (ctx->skipping()) {
|
||||
} else if (lhs.opt) {
|
||||
if (lhs.opt->is_scalar())
|
||||
rhs_value.throw_exception("Cannot assign a vector value to a scalar variable.");
|
||||
rhs_value.throw_exception(L("Cannot assign a vector value to a scalar variable."));
|
||||
OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true };
|
||||
vector_variable_assign_expr_with_count(ctx, lhs_opt, rhs_count, rhs_value);
|
||||
} else {
|
||||
@@ -1566,7 +1568,7 @@ namespace client
|
||||
if (! ctx->skipping()) {
|
||||
check_writable(ctx, lhs);
|
||||
if (lhs.opt->is_scalar())
|
||||
rhs_value.throw_exception("Cannot assign a vector value to a scalar variable.");
|
||||
rhs_value.throw_exception(L("Cannot assign a vector value to a scalar variable."));
|
||||
vector_variable_assign_expr_with_count(ctx, lhs, rhs_count, rhs_value);
|
||||
}
|
||||
}
|
||||
@@ -1595,13 +1597,13 @@ namespace client
|
||||
// scalar_var = ()
|
||||
// or
|
||||
// scalar_var = ( scalar, scalar, ... )
|
||||
ctx->throw_exception("Cannot assign a vector value to a scalar variable.", lhs.it_range);
|
||||
ctx->throw_exception(L("Cannot assign a vector value to a scalar variable."), lhs.it_range);
|
||||
}
|
||||
|
||||
auto check_numeric_vector = [](const std::vector<expr> &il) {
|
||||
for (auto &i : il)
|
||||
if (! i.numeric_type())
|
||||
i.throw_exception("Right side is not a numeric expression");
|
||||
i.throw_exception(L("Right side is not a numeric expression"));
|
||||
};
|
||||
|
||||
ConfigOption *opt = const_cast<ConfigOption*>(lhs.opt);
|
||||
@@ -1620,7 +1622,7 @@ namespace client
|
||||
case coBools:
|
||||
for (auto &i : il)
|
||||
if (i.type() != expr::TYPE_BOOL)
|
||||
i.throw_exception("Right side is not a boolean expression");
|
||||
i.throw_exception(L("Right side is not a boolean expression"));
|
||||
fill_vector_from_initializer_list<ConfigOptionBools>(opt, il, [](auto &v){ return v.b(); });
|
||||
break;
|
||||
default: assert(false);
|
||||
@@ -1642,7 +1644,7 @@ namespace client
|
||||
vector_variable_assign_initializer_list(ctx, lhs_opt, il);
|
||||
} else {
|
||||
if (il.empty())
|
||||
ctx->throw_exception("Cannot create vector variable from an empty initializer list, because its type cannot be deduced.", lhs.it_range);
|
||||
ctx->throw_exception(L("Cannot create vector variable from an empty initializer list, because its type cannot be deduced."), lhs.it_range);
|
||||
// Allocate a new vector variable.
|
||||
// First guesstimate type of the output vector.
|
||||
size_t num_bool = 0;
|
||||
@@ -1663,7 +1665,7 @@ namespace client
|
||||
opt_new = std::make_unique<ConfigOptionStrings>();
|
||||
else if (num_bool > 0) {
|
||||
if (num_double + num_int > 0)
|
||||
ctx->throw_exception("Right side is not valid: Mixing numeric and boolean types.", IteratorRange{ il.front().it_range.begin(), il.back().it_range.end() });
|
||||
ctx->throw_exception(L("Right side is not valid: Mixing numeric and boolean types."), IteratorRange{ il.front().it_range.begin(), il.back().it_range.end() });
|
||||
opt_new = std::make_unique<ConfigOptionBools>();
|
||||
} else {
|
||||
// Output is numeric.
|
||||
@@ -1695,22 +1697,22 @@ namespace client
|
||||
check_writable(ctx, lhs);
|
||||
assert(lhs.opt->is_vector());
|
||||
if (rhs.has_index() || ! rhs.opt->is_vector())
|
||||
ctx->throw_exception("Cannot assign scalar to a vector", lhs.it_range);
|
||||
ctx->throw_exception(L("Cannot assign scalar to a vector"), lhs.it_range);
|
||||
if (rhs.opt->is_nil())
|
||||
ctx->throw_exception("Some elements of the right hand side vector variable of optional values are undefined (nil)", rhs.it_range);
|
||||
ctx->throw_exception(L("Some elements of the right hand side vector variable of optional values are undefined (nil)"), rhs.it_range);
|
||||
if (lhs.opt->type() != rhs.opt->type()) {
|
||||
// Vector types are not compatible.
|
||||
switch (lhs.opt->type()) {
|
||||
case coFloats:
|
||||
ctx->throw_exception("Left hand side is a float vector, while the right hand side is not.", lhs.it_range);
|
||||
ctx->throw_exception(L("Left hand side is a float vector, while the right hand side is not."), lhs.it_range);
|
||||
case coInts:
|
||||
ctx->throw_exception("Left hand side is an int vector, while the right hand side is not.", lhs.it_range);
|
||||
ctx->throw_exception(L("Left hand side is an int vector, while the right hand side is not."), lhs.it_range);
|
||||
case coStrings:
|
||||
ctx->throw_exception("Left hand side is a string vector, while the right hand side is not.", lhs.it_range);
|
||||
ctx->throw_exception(L("Left hand side is a string vector, while the right hand side is not."), lhs.it_range);
|
||||
case coBools:
|
||||
ctx->throw_exception("Left hand side is a bool vector, while the right hand side is not.", lhs.it_range);
|
||||
ctx->throw_exception(L("Left hand side is a bool vector, while the right hand side is not."), lhs.it_range);
|
||||
default:
|
||||
ctx->throw_exception("Left hand side / right hand side vectors are not compatible.", lhs.it_range);
|
||||
ctx->throw_exception(L("Left hand side / right hand side vectors are not compatible."), lhs.it_range);
|
||||
}
|
||||
}
|
||||
const_cast<ConfigOption*>(lhs.opt)->set(rhs.opt);
|
||||
@@ -1735,7 +1737,7 @@ namespace client
|
||||
// Stop parsing, let the other rules resolve this case.
|
||||
return false;
|
||||
if (rhs.opt->is_nil())
|
||||
ctx->throw_exception("Some elements of the right hand side vector variable of optional values are undefined (nil)", rhs.it_range);
|
||||
ctx->throw_exception(L("Some elements of the right hand side vector variable of optional values are undefined (nil)"), rhs.it_range);
|
||||
// Clone the vector variable.
|
||||
std::unique_ptr<ConfigOption> opt_new;
|
||||
if (one_of(rhs.opt->type(), { coFloats, coInts, coStrings, coBools }))
|
||||
@@ -1743,7 +1745,7 @@ namespace client
|
||||
else if (rhs.opt->type() == coPercents)
|
||||
opt_new = std::make_unique<ConfigOptionFloats>(static_cast<const ConfigOptionPercents*>(rhs.opt)->values);
|
||||
else
|
||||
ctx->throw_exception("Duplicating this type of vector variable is not supported", rhs.it_range);
|
||||
ctx->throw_exception(L("Duplicating this type of vector variable is not supported"), rhs.it_range);
|
||||
const_cast<MyContext*>(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable);
|
||||
}
|
||||
// Continue parsing.
|
||||
@@ -1761,7 +1763,7 @@ namespace client
|
||||
{
|
||||
if (! ctx->skipping()) {
|
||||
if (opt.has_index() || ! opt.opt->is_vector())
|
||||
ctx->throw_exception("parameter of empty() is not a vector variable", opt.it_range);
|
||||
ctx->throw_exception(L("parameter of empty() is not a vector variable"), opt.it_range);
|
||||
out.set_b(static_cast<const ConfigOptionVectorBase*>(opt.opt)->size() == 0);
|
||||
}
|
||||
out.it_range = opt.it_range;
|
||||
@@ -1771,7 +1773,7 @@ namespace client
|
||||
{
|
||||
if (! ctx->skipping()) {
|
||||
if (opt.has_index() || ! opt.opt->is_vector())
|
||||
ctx->throw_exception("parameter of size() is not a vector variable", opt.it_range);
|
||||
ctx->throw_exception(L("parameter of size() is not a vector variable"), opt.it_range);
|
||||
out.set_i(int(static_cast<const ConfigOptionVectorBase*>(opt.opt)->size()));
|
||||
}
|
||||
out.it_range = opt.it_range;
|
||||
@@ -1783,7 +1785,7 @@ namespace client
|
||||
{
|
||||
if (expr_index.type() != expr::TYPE_EMPTY) {
|
||||
if (expr_index.type() != expr::TYPE_INT)
|
||||
expr_index.throw_exception("Non-integer index is not allowed to address a vector variable.");
|
||||
expr_index.throw_exception(L("Non-integer index is not allowed to address a vector variable."));
|
||||
output = expr_index.i();
|
||||
}
|
||||
}
|
||||
@@ -1794,7 +1796,7 @@ namespace client
|
||||
return;
|
||||
|
||||
if (ctx->context_data == nullptr)
|
||||
ctx->throw_exception("Random number generator not available in this context.",
|
||||
ctx->throw_exception(L("Random number generator not available in this context."),
|
||||
IteratorRange(param1.it_range.begin(), param2.it_range.end()));
|
||||
expr::random(param1, param2, ctx->context_data->rng);
|
||||
}
|
||||
@@ -1832,21 +1834,20 @@ namespace client
|
||||
auto error_line = std::string(first, first_pos) + std::string(last, 0, last_pos);
|
||||
// Position of the it_error from the start of its line.
|
||||
auto error_pos = (it_error - it_begin) - first_pos;
|
||||
msg += "Parsing error at line " + std::to_string(line_nr);
|
||||
if (! info.tag.empty() && info.tag.front() == '*') {
|
||||
// The gat contains an explanatory string.
|
||||
msg += ": ";
|
||||
msg += info.tag.substr(1);
|
||||
// TRN Custom G-code error. %1% is the line number, %2% the reason.
|
||||
msg += Slic3r::format(_u8L("Parsing error at line %1%: %2%"), line_nr, Slic3r::I18N::translate(info.tag.substr(1)));
|
||||
} else {
|
||||
auto it = tag_to_error_message.find(info.tag);
|
||||
if (it == tag_to_error_message.end()) {
|
||||
// A generic error report based on the nonterminal or terminal symbol name.
|
||||
msg += ". Expecting tag ";
|
||||
msg += info.tag;
|
||||
// TRN Custom G-code error. %1% is the line number, %2% the name of a grammar rule.
|
||||
msg += Slic3r::format(_u8L("Parsing error at line %1%. Expecting tag %2%"), line_nr, info.tag);
|
||||
} else {
|
||||
// Use the human readable error message.
|
||||
msg += ". ";
|
||||
msg += it->second;
|
||||
// TRN Custom G-code error. %1% is the line number, %2% the reason.
|
||||
msg += Slic3r::format(_u8L("Parsing error at line %1%. %2%"), line_nr, Slic3r::I18N::translate(it->second));
|
||||
}
|
||||
}
|
||||
msg += '\n';
|
||||
@@ -1877,15 +1878,15 @@ namespace client
|
||||
static void init(const expr &x) {
|
||||
if (x.type() != expr::TYPE_EMPTY) {
|
||||
if (!x.numeric_type())
|
||||
x.throw_exception("Interpolation value must be a number.");
|
||||
x.throw_exception(L("Interpolation value must be a number."));
|
||||
}
|
||||
}
|
||||
static void add_pair(const expr &x, const expr &y, InterpolateTableContext &table) {
|
||||
if (x.type() != expr::TYPE_EMPTY) {
|
||||
if (! x.numeric_type())
|
||||
x.throw_exception("X value of a table point must be a number.");
|
||||
x.throw_exception(L("X value of a table point must be a number."));
|
||||
if (! y.numeric_type())
|
||||
y.throw_exception("Y value of a table point must be a number.");
|
||||
y.throw_exception(L("Y value of a table point must be a number."));
|
||||
table.table.push_back({ x.as_d(), x.it_range, y.as_d() });
|
||||
}
|
||||
}
|
||||
@@ -1902,7 +1903,7 @@ namespace client
|
||||
double x1 = table.table[i].x;
|
||||
if (x0 > x1)
|
||||
boost::throw_exception(qi::expectation_failure(
|
||||
table.table[i - 1].it_range_x.begin(), table.table[i].it_range_x.end(), spirit::info("X coordinates of the table must be increasing")));
|
||||
table.table[i - 1].it_range_x.begin(), table.table[i].it_range_x.end(), spirit::info(std::string("*") + L("X coordinates of the table must be increasing"))));
|
||||
if (! evaluated && x >= x0 && x <= x1) {
|
||||
double y0 = table.table[i - 1].y;
|
||||
double y1 = table.table[i].y;
|
||||
@@ -1925,7 +1926,7 @@ namespace client
|
||||
out.set_d(table.table.back().y);
|
||||
else
|
||||
// The value is really outside the table range.
|
||||
expr_x.throw_exception("Interpolation value is outside the table range");
|
||||
expr_x.throw_exception(L("Interpolation value is outside the table range"));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1939,30 +1940,30 @@ namespace client
|
||||
|
||||
// Table to translate symbol tag to a human readable error message.
|
||||
std::map<std::string, std::string> MyContext::tag_to_error_message = {
|
||||
{ "eoi", "Unknown syntax error" },
|
||||
{ "start", "Unknown syntax error" },
|
||||
{ "text", "Invalid text." },
|
||||
{ "text_block", "Invalid text block." },
|
||||
{ "macro", "Invalid macro." },
|
||||
{ "repeat", "Unknown syntax error" },
|
||||
{ "if_else_output", "Not an {if}{else}{endif} macro." },
|
||||
{ "switch_output", "Not a {switch} macro." },
|
||||
{ "legacy_variable_expansion", "Expecting a legacy variable expansion format" },
|
||||
{ "identifier", "Expecting an identifier." },
|
||||
{ "conditional_expression", "Expecting a conditional expression." },
|
||||
{ "logical_or_expression", "Expecting a boolean expression." },
|
||||
{ "logical_and_expression", "Expecting a boolean expression." },
|
||||
{ "equality_expression", "Expecting an expression." },
|
||||
{ "bool_expr_eval", "Expecting a boolean expression."},
|
||||
{ "relational_expression", "Expecting an expression." },
|
||||
{ "additive_expression", "Expecting an expression." },
|
||||
{ "multiplicative_expression", "Expecting an expression." },
|
||||
{ "unary_expression", "Expecting an expression." },
|
||||
{ "optional_parameter", "Expecting a closing brace or an optional parameter." },
|
||||
{ "one_of_list", "Expecting a list of string patterns (simple text or rexep)" },
|
||||
{ "variable_reference", "Expecting a variable reference."},
|
||||
{ "variable", "Expecting a variable name."},
|
||||
{ "regular_expression", "Expecting a regular expression."}
|
||||
{ "eoi", L("Unknown syntax error") },
|
||||
{ "start", L("Unknown syntax error") },
|
||||
{ "text", L("Invalid text.") },
|
||||
{ "text_block", L("Invalid text block.") },
|
||||
{ "macro", L("Invalid macro.") },
|
||||
{ "repeat", L("Unknown syntax error") },
|
||||
{ "if_else_output", L("Not an {if}{else}{endif} macro.") },
|
||||
{ "switch_output", L("Not a {switch} macro.") },
|
||||
{ "legacy_variable_expansion", L("Expecting a legacy variable expansion format") },
|
||||
{ "identifier", L("Expecting an identifier.") },
|
||||
{ "conditional_expression", L("Expecting a conditional expression.") },
|
||||
{ "logical_or_expression", L("Expecting a boolean expression.") },
|
||||
{ "logical_and_expression", L("Expecting a boolean expression.") },
|
||||
{ "equality_expression", L("Expecting an expression.") },
|
||||
{ "bool_expr_eval", L("Expecting a boolean expression.")},
|
||||
{ "relational_expression", L("Expecting an expression.") },
|
||||
{ "additive_expression", L("Expecting an expression.") },
|
||||
{ "multiplicative_expression", L("Expecting an expression.") },
|
||||
{ "unary_expression", L("Expecting an expression.") },
|
||||
{ "optional_parameter", L("Expecting a closing brace or an optional parameter.") },
|
||||
{ "one_of_list", L("Expecting a list of string patterns (simple text or regexp)") },
|
||||
{ "variable_reference", L("Expecting a variable reference.")},
|
||||
{ "variable", L("Expecting a variable name.")},
|
||||
{ "regular_expression", L("Expecting a regular expression.")}
|
||||
};
|
||||
|
||||
// For debugging the boost::spirit parsers. Print out the string enclosed in it_range.
|
||||
@@ -2031,7 +2032,7 @@ namespace client
|
||||
first = it;
|
||||
return true;
|
||||
err:
|
||||
MyContext::throw_exception("Invalid utf8 sequence", IteratorRange(first, last));
|
||||
MyContext::throw_exception(L("Invalid utf8 sequence"), IteratorRange(first, last));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2057,7 +2058,7 @@ namespace client
|
||||
return false;
|
||||
char c = *first;
|
||||
if (it - first > 1 || c < 0)
|
||||
MyContext::throw_exception("Non-ASCII7 characters are only allowed inside text blocks and string literals, not inside code blocks.", IteratorRange(first, it));
|
||||
MyContext::throw_exception(L("Non-ASCII7 characters are only allowed inside text blocks and string literals, not inside code blocks."), IteratorRange(first, it));
|
||||
if (c == '\r' || c == '\n' || c == '\t' || c == ' ') {
|
||||
// Skip the whitespaces
|
||||
++ first;
|
||||
@@ -2116,7 +2117,7 @@ namespace client
|
||||
if (*it == '\\') {
|
||||
if (++ it == end ||
|
||||
(*it != 'r' && *it != 'n' && *it != '"' && *it != '\\'))
|
||||
ctx->throw_exception("Invalid escape sequence", {std::prev(it), std::next(it) });
|
||||
ctx->throw_exception(L("Invalid escape sequence"), {std::prev(it), std::next(it) });
|
||||
++ len;
|
||||
++ it;
|
||||
} else {
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "Semver.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
#include "I18N.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@@ -4640,10 +4641,10 @@ void PhysicalPrinterCollection::load_printers(
|
||||
printer.loaded = true;
|
||||
}
|
||||
catch (const std::ifstream::failure& err) {
|
||||
throw Slic3r::RuntimeError(std::string("The selected preset cannot be loaded: ") + printer.file + "\n\tReason: " + err.what());
|
||||
throw Slic3r::RuntimeError((boost::format(_u8L("The selected preset cannot be loaded: %1%\n\tReason: %2%")) % printer.file % err.what()).str());
|
||||
}
|
||||
catch (const std::runtime_error& err) {
|
||||
throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + printer.file + "\n\tReason: " + err.what());
|
||||
throw Slic3r::RuntimeError((boost::format(_u8L("Failed loading the preset file: %1%\n\tReason: %2%")) % printer.file % err.what()).str());
|
||||
}
|
||||
printers_loaded.emplace_back(printer);
|
||||
}
|
||||
|
||||
@@ -809,7 +809,7 @@ void PresetBundle::setup_directories()
|
||||
BOOST_LOG_TRIVIAL(warning) << boost::format("creating directory %1% failed, maybe created by other instance, go on!")%subdir.string();
|
||||
}
|
||||
else
|
||||
throw Slic3r::RuntimeError(std::string("Unable to create directory ") + subdir.string());
|
||||
throw Slic3r::RuntimeError((boost::format(L("Unable to create directory %1%")) % subdir.string()).str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5451,7 +5451,7 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw
|
||||
|
||||
//BBS: add config related logs
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" can not load config file %1% not from gcode")%path ;
|
||||
throw Slic3r::RuntimeError(std::string("Unknown configuration file: ") + path);
|
||||
throw Slic3r::RuntimeError((boost::format(L("Unknown configuration file: %1%")) % path).str());
|
||||
|
||||
return ConfigSubstitutions{};
|
||||
}
|
||||
@@ -5653,7 +5653,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
ConfigOptionStrings* filament_colour_option = config.option<ConfigOptionStrings>("filament_colour");
|
||||
size_t num_filaments = filament_colour_option?filament_colour_option->size():0;
|
||||
if (num_filaments == 0)
|
||||
throw Slic3r::RuntimeError(std::string("Invalid configuration file: ") + name_or_path);
|
||||
throw Slic3r::RuntimeError((boost::format(L("Invalid configuration file: %1%")) % name_or_path).str());
|
||||
#endif
|
||||
|
||||
//BBS: add config related logs
|
||||
@@ -5717,7 +5717,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
|| (extruder_variant_count < num_filaments)) {
|
||||
assert(false);
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": invalid config file %1%, can not find suitable filament_extruder_variant or filament_self_index") % name_or_path;
|
||||
throw Slic3r::RuntimeError(std::string("Invalid configuration file: ") + name_or_path);
|
||||
throw Slic3r::RuntimeError((boost::format(L("Invalid configuration file: %1%")) % name_or_path).str());
|
||||
}
|
||||
if (num_filaments != extruder_variant_count) {
|
||||
process_multi_extruder = true;
|
||||
@@ -6151,8 +6151,9 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
// A payload mix authored at the same slot (a mix inside the physical region) is
|
||||
// processed after this sweep and overrides its own destination below.
|
||||
published_config->mixed_slot_relocations.insert_or_assign(int(slot), int(dest));
|
||||
published_config->material_replacements.emplace_back("slot " + std::to_string(slot) + " -> slot " +
|
||||
std::to_string(dest) + ": mixed filament");
|
||||
// TRN Filament slot change after loading a published project. %1% and %2% are slot numbers.
|
||||
published_config->material_replacements.emplace_back(
|
||||
(boost::format(L("slot %1% -> slot %2%: mixed filament")) % slot % dest).str());
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": published 3MF relocated receiver mixed filament slot " << slot
|
||||
<< " -> " << dest << " (physical-first rebalance)";
|
||||
}
|
||||
@@ -6186,9 +6187,10 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
// No free virtual slot left: report instead of destroying a real filament.
|
||||
// The local skipped_keys is published wholesale at the end of the pass;
|
||||
// writing published_config->skipped_keys here would be clobbered by it.
|
||||
skipped_keys.emplace_back("material:" + material_label + (is_payload_mix ?
|
||||
" (mixed filament definition: filament slot limit reached)" :
|
||||
" (filament slot limit reached)"));
|
||||
skipped_keys.emplace_back("material:" + material_label + " (" +
|
||||
(is_payload_mix ? L("mixed filament definition: filament slot limit reached") :
|
||||
L("filament slot limit reached")) +
|
||||
")");
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": published 3MF " << (is_payload_mix ? "mixed filament definition" : "material")
|
||||
<< " from slot " << entry.slot << " could not be placed: all " << next_free_slot
|
||||
<< " slots exhausted";
|
||||
@@ -6200,8 +6202,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
// sidebar's mixed section needs two physical filaments to mix), so a
|
||||
// placeholder would be invisible and unfixable: drop the entry and
|
||||
// report it like any other unappliable input.
|
||||
skipped_keys.emplace_back("material:" + material_label + " (printer supports only " +
|
||||
std::to_string(physical_capacity) + " filament)");
|
||||
skipped_keys.emplace_back("material:" + material_label + " (" +
|
||||
(boost::format(L("the printer's filament limit is %1%")) % physical_capacity).str() + ")");
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": published 3MF material from slot " << entry.slot
|
||||
<< " dropped: printer supports only " << physical_capacity << " filament";
|
||||
entry_it = published_config->material_keys.erase(entry_it);
|
||||
@@ -6219,8 +6221,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
any_mixed_relocated = true;
|
||||
mixed_moves.emplace_back(size_t(authored_slot), size_t(entry.slot));
|
||||
published_config->mixed_slot_relocations.insert_or_assign(authored_slot, entry.slot);
|
||||
published_config->material_replacements.emplace_back("slot " + std::to_string(authored_slot) + " -> slot " +
|
||||
std::to_string(entry.slot) + ": mixed filament");
|
||||
published_config->material_replacements.emplace_back(
|
||||
(boost::format(L("slot %1% -> slot %2%: mixed filament")) % authored_slot % entry.slot).str());
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": published 3MF relocated mixed filament slot " << authored_slot
|
||||
<< " -> " << entry.slot;
|
||||
++entry_it;
|
||||
@@ -6238,10 +6240,11 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
published_config->mixed_slot_relocations.insert_or_assign(authored_slot, dest_slot);
|
||||
}
|
||||
published_config->material_replacements.emplace_back(
|
||||
(dest_slot != authored_slot ?
|
||||
"slot " + std::to_string(authored_slot) + " -> slot " + std::to_string(dest_slot) :
|
||||
"slot " + std::to_string(dest_slot)) +
|
||||
": unassigned mixed filament (printer supports only " + std::to_string(physical_capacity) + " filaments)");
|
||||
dest_slot != authored_slot ?
|
||||
(boost::format(L("slot %1% -> slot %2%: unassigned mixed filament (the printer's filament limit is %3%)")) %
|
||||
authored_slot % dest_slot % physical_capacity).str() :
|
||||
(boost::format(L("slot %1%: unassigned mixed filament (the printer's filament limit is %2%)")) % dest_slot %
|
||||
physical_capacity).str());
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": published 3MF material from slot " << authored_slot
|
||||
<< " placed as an unassigned mixed filament at slot " << dest_slot
|
||||
<< " (printer supports only " << physical_capacity << " filaments)";
|
||||
@@ -6463,8 +6466,9 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
this->filament_presets[slot] = replacement;
|
||||
material_applied = true;
|
||||
// The re-point used to be silent; surface it like the other slot changes.
|
||||
published_config->material_replacements.emplace_back("slot " + std::to_string(slot) + ": " + aliased_name + " -> " +
|
||||
replacement);
|
||||
// TRN Filament slot change after loading a published project. %1% is the slot number, %2% the old preset, %3% the new one.
|
||||
published_config->material_replacements.emplace_back(
|
||||
(boost::format(L("slot %1%: %2% -> %3%")) % slot % aliased_name % replacement).str());
|
||||
}
|
||||
// Grow the per-slot colour/type/map project vectors to the new slot count and
|
||||
// seed the new entries so the slots render with colours instead of blank chips
|
||||
@@ -6659,8 +6663,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
// definition below.
|
||||
if (is_mixed_definition(entry) && !this->is_mixed_filament(slot)) {
|
||||
finalize_mixed_placeholder(slot);
|
||||
published_config->material_replacements.emplace_back("slot " + std::to_string(slot) +
|
||||
": mixed filament definition could not be imported");
|
||||
published_config->material_replacements.emplace_back(
|
||||
(boost::format(L("slot %1%: mixed filament definition could not be imported")) % slot).str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -6687,17 +6691,18 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
if (comps.size() < 2)
|
||||
// An empty definition cell counts as broken too: applying it
|
||||
// would ship a mix the sidebar would only flag later.
|
||||
mix_error = "needs at least two components";
|
||||
mix_error = L("needs at least two components");
|
||||
else
|
||||
for (unsigned int comp : comps)
|
||||
if (comp < 1 || size_t(comp) > mixed_final_slot_count ||
|
||||
mixed_final_slots.count(int(comp) - 1) != 0) {
|
||||
mix_error = "components reference missing slots";
|
||||
mix_error = L("components reference missing slots");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mix_error.empty()) {
|
||||
skipped_keys.emplace_back("material:" + material_label + " (mixed filament definition: " + mix_error + ")");
|
||||
skipped_keys.emplace_back("material:" + material_label + " (" +
|
||||
(boost::format(L("mixed filament definition: %1%")) % mix_error).str() + ")");
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": published 3MF mixed filament from slot " << entry.slot
|
||||
<< " rejected: " << mix_error;
|
||||
// Degradation, not silent corruption: the slot was already grown and
|
||||
@@ -6713,9 +6718,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
// is reported as skipped above.
|
||||
if (!this->is_mixed_filament(slot)) {
|
||||
finalize_mixed_placeholder(slot);
|
||||
published_config->material_replacements.emplace_back("slot " + std::to_string(slot) +
|
||||
": mixed filament definition could not be imported (" +
|
||||
mix_error + ")");
|
||||
published_config->material_replacements.emplace_back(
|
||||
(boost::format(L("slot %1%: mixed filament definition could not be imported (%2%)")) % slot % mix_error).str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -6786,8 +6790,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
const std::string old_name = this->filament_presets[slot];
|
||||
this->filament_presets[slot] = new_name;
|
||||
material_applied = true;
|
||||
published_config->material_replacements.emplace_back("slot " + std::to_string(slot) + ": " + old_name + " -> " +
|
||||
new_name);
|
||||
published_config->material_replacements.emplace_back(
|
||||
(boost::format(L("slot %1%: %2% -> %3%")) % slot % old_name % new_name).str());
|
||||
// Colour is slot-scoped and project-visible: sync into project_config
|
||||
// (the copy already baked it, this makes the chips render).
|
||||
if (entry.publish_color && !entry.color.empty()) {
|
||||
@@ -6906,11 +6910,12 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
<< " (score " << score << ", preset_name \"" << entry.preset_name << "\", filament_id \""
|
||||
<< entry.filament_id << "\", setting_id \"" << entry.setting_id << "\", type \""
|
||||
<< entry.publish_type_value << "\")";
|
||||
std::string replacement_line = "slot " + std::to_string(slot) + ": " + old_name + " -> " + replacement;
|
||||
// A pick that is not the exact published material is a substitute;
|
||||
// an entry without identity fields cannot be judged, so it stays plain.
|
||||
if (score < 2 && (!entry.filament_id.empty() || !entry.filament_vendor.empty()))
|
||||
replacement_line += " (substitute)";
|
||||
const bool is_substitute = score < 2 && (!entry.filament_id.empty() || !entry.filament_vendor.empty());
|
||||
std::string replacement_line = (boost::format(is_substitute ? L("slot %1%: %2% -> %3% (substitute)") :
|
||||
L("slot %1%: %2% -> %3%")) %
|
||||
slot % old_name % replacement).str();
|
||||
published_config->material_replacements.emplace_back(std::move(replacement_line));
|
||||
} else {
|
||||
// Partial publish with no replacement: keep the receiver's
|
||||
@@ -6926,8 +6931,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
// mix is left untouched).
|
||||
if (is_mixed_definition(entry) && !this->is_mixed_filament(slot)) {
|
||||
finalize_mixed_placeholder(slot);
|
||||
published_config->material_replacements.emplace_back("slot " + std::to_string(slot) +
|
||||
": mixed filament definition could not be imported");
|
||||
published_config->material_replacements.emplace_back(
|
||||
(boost::format(L("slot %1%: mixed filament definition could not be imported")) % slot).str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7010,8 +7015,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
if (!this->is_mixed_filament(size_t(gap_slot))) {
|
||||
finalize_mixed_placeholder(size_t(gap_slot));
|
||||
published_config->material_replacements.emplace_back(
|
||||
"slot " + std::to_string(gap_slot) +
|
||||
": unassigned mixed filament (printer supports only " + std::to_string(physical_capacity) + " filaments)");
|
||||
(boost::format(L("slot %1%: unassigned mixed filament (the printer's filament limit is %2%)")) % gap_slot %
|
||||
physical_capacity).str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7064,7 +7069,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
|
||||
static ConfigurationError failed_loading_error(const std::string& file, const std::string& dir)
|
||||
{
|
||||
return ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % file % dir).str());
|
||||
return ConfigurationError((boost::format(L("Failed loading configuration file %1%\nSuggest cleaning the directory %2% first")) % file % dir).str());
|
||||
}
|
||||
|
||||
void PresetBundle::log_errors(const std::vector<std::string>& errors)
|
||||
@@ -7537,7 +7542,8 @@ void PresetBundle::parse_vendor_json(VendorRead& read)
|
||||
auto config_version = Semver::parse(version_str);
|
||||
if (! config_version) {
|
||||
++m_errors;
|
||||
throw ConfigurationError((boost::format("vendor %1%'s config version: %2% invalid\nSuggest cleaning the directory %3% firstly")
|
||||
// TRN %1% is the vendor name, %2% the version found in its profile, %3% the profile directory.
|
||||
throw ConfigurationError((boost::format(L("Vendor %1%'s config version: %2% invalid\nSuggest cleaning the directory %3% first"))
|
||||
% vendor_name % version_str % dir).str());
|
||||
} else {
|
||||
vendor_profile.config_version = std::move(*config_version);
|
||||
@@ -7575,7 +7581,7 @@ void PresetBundle::parse_vendor_json(VendorRead& read)
|
||||
}
|
||||
catch(nlohmann::detail::parse_error &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<<root_file<<" got a nlohmann::detail::parse_error, reason = " << err.what();
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%: %2%\nSuggest cleaning the directory %3% firstly")
|
||||
throw ConfigurationError((boost::format(L("Failed loading configuration file %1%: %2%\nSuggest cleaning the directory %3% first"))
|
||||
%root_file %err.what() % dir).str());
|
||||
//goto __error_process;
|
||||
}
|
||||
@@ -7690,7 +7696,7 @@ void PresetBundle::parse_vendor_json(VendorRead& read)
|
||||
}
|
||||
catch(nlohmann::detail::parse_error &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<< subfile <<" got a nlohmann::detail::parse_error, reason = " << err.what();
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%: %2%\nSuggest cleaning the directory %3% firstly")
|
||||
throw ConfigurationError((boost::format(L("Failed loading configuration file %1%: %2%\nSuggest cleaning the directory %3% first"))
|
||||
%subfile %err.what() % dir).str());
|
||||
}
|
||||
|
||||
|
||||
+26
-20
@@ -1484,7 +1484,7 @@ static StringObjectException layered_print_cleareance_valid(const Print &print,
|
||||
// return {inst->model_instance->get_object()->name + L(" is too close to exclusion area, there may be collisions when printing.") + "\n",
|
||||
// inst->model_instance->get_object()};
|
||||
//ORCA: Pass ModelInstance instead of ModelObject
|
||||
return {inst->model_instance->get_object()->name + L(" is too close to exclusion area, there may be collisions when printing.") + "\n",
|
||||
return {(boost::format(L("%1% is too close to exclusion area. There may be collisions when printing.")) % inst->model_instance->get_object()->name).str() + "\n",
|
||||
inst->model_instance};
|
||||
}
|
||||
|
||||
@@ -1492,7 +1492,7 @@ static StringObjectException layered_print_cleareance_valid(const Print &print,
|
||||
// return {inst->model_instance->get_object()->name + L(" is too close to clumping detection area, there may be collisions when printing.") + "\n",
|
||||
// inst->model_instance->get_object()};
|
||||
//ORCA: Pass ModelInstance instead of ModelObject
|
||||
return {inst->model_instance->get_object()->name + L(" is too close to clumping detection area, there may be collisions when printing.") + "\n",
|
||||
return {(boost::format(L("%1% is too close to the clumping detection area. There may be collisions when printing.")) % inst->model_instance->get_object()->name).str() + "\n",
|
||||
inst->model_instance};
|
||||
}
|
||||
current_instance_hulls.emplace_back(volume_hull);
|
||||
@@ -1577,20 +1577,20 @@ static StringObjectException layered_print_cleareance_valid(const Print &print,
|
||||
// many setups that print fine.
|
||||
if (!intersection(convex_hulls_other, convex_hulls_temp).empty()) {
|
||||
if (warning) {
|
||||
warning->string += L("Prime Tower") + L(" is too close to others, and collisions may be caused.\n");
|
||||
warning->string += L("Prime tower is too close to others, and collisions may be caused.\n");
|
||||
}
|
||||
}
|
||||
if (!intersection(exclude_polys, tower_polys_checked).empty()) {
|
||||
return {L("Prime Tower") + L(" is too close to an exclusion area, and collisions will be caused.\n")};
|
||||
return {L("Prime tower is too close to an exclusion area, and collisions will be caused.\n")};
|
||||
}
|
||||
if (print_config.enable_wrapping_detection.value && !intersection({wrapping_poly}, tower_polys_checked).empty()) {
|
||||
return {L("Prime Tower") + L(" is too close to clumping detection area, and collisions will be caused.\n")};
|
||||
return {L("Prime tower is too close to the clumping detection area, and collisions will be caused.\n")};
|
||||
}
|
||||
if (warning && !intersection(exclude_polys, tower_polys_estimated).empty()) {
|
||||
warning->string += L("Prime Tower") + L(" is too close to exclusion area, there may be collisions when printing.") + "\n";
|
||||
warning->string += L("Prime tower is too close to an exclusion area. There may be collisions when printing.") + "\n";
|
||||
}
|
||||
if (warning && print_config.enable_wrapping_detection.value && !intersection({wrapping_poly}, tower_polys_estimated).empty()) {
|
||||
warning->string += L("Prime Tower") + L(" is too close to clumping detection area, there may be collisions when printing.") + "\n";
|
||||
warning->string += L("Prime tower is too close to the clumping detection area. There may be collisions when printing.") + "\n";
|
||||
}
|
||||
// No gate on "is there a tower": one that is not printed estimates to zero, so the hulls
|
||||
// are degenerate and every check passes. Re-deriving it here missed the wrapping-detection
|
||||
@@ -1600,9 +1600,9 @@ static StringObjectException layered_print_cleareance_valid(const Print &print,
|
||||
for (Polygon &p : printable_polys)
|
||||
p.translate(plate_shift);
|
||||
if (!diff(tower_polys_checked, printable_polys).empty())
|
||||
return {L("Prime Tower") + L(" is partially outside the printable area, and it cannot be printed.\n")};
|
||||
return {L("Prime tower is partially outside the printable area, and it cannot be printed.\n")};
|
||||
if (warning && !diff(tower_polys_estimated, printable_polys).empty())
|
||||
warning->string += L("Prime Tower") + L(" is partially outside the printable area, and it cannot be printed.\n");
|
||||
warning->string += L("Prime tower is partially outside the printable area, and it cannot be printed.\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1969,14 +1969,19 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
|
||||
// What is left is a printer with more filaments than logical extruders, where
|
||||
// the tail slots fall outside the map. Narrow, but without this the sentence
|
||||
// ends in a dangling "on .".
|
||||
if (routed_list.empty())
|
||||
routed_list = L("no configured tool");
|
||||
|
||||
StringObjectException err;
|
||||
err.string = Slic3r::format(
|
||||
L("IDEX/IQEX mode \"%1%\" prints with T%2%, but this plate's filaments are on %3%. "
|
||||
"Assign a filament loaded on T%2%, or switch this plate to Primary mode."),
|
||||
parallel_mode, routing.primary_phys, routed_list);
|
||||
if (routed_list.empty())
|
||||
err.string = Slic3r::format(
|
||||
// TRN %1% is the IDEX/IQEX mode name, %2% the tool number.
|
||||
L("IDEX/IQEX mode \"%1%\" prints with T%2%, but none of this plate's filaments are on a configured tool. "
|
||||
"Assign a filament loaded on T%2%, or switch this plate to Primary mode."),
|
||||
parallel_mode, routing.primary_phys);
|
||||
else
|
||||
err.string = Slic3r::format(
|
||||
// TRN %1% is the IDEX/IQEX mode name, %2% the tool number, %3% a list of tools such as "T1, T2".
|
||||
L("IDEX/IQEX mode \"%1%\" prints with T%2%, but this plate's filaments are on %3%. "
|
||||
"Assign a filament loaded on T%2%, or switch this plate to Primary mode."),
|
||||
parallel_mode, routing.primary_phys, routed_list);
|
||||
// Gives the notification a "Jump to <object>" link, which selects the object
|
||||
// and switches to Prepare -- directly enabling the first suggested remedy.
|
||||
err.object = m_objects.front();
|
||||
@@ -3458,7 +3463,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
m_tool_ordering = ToolOrdering(*this, -1, false);
|
||||
m_tool_ordering.sort_and_build_data(*this, -1, false);
|
||||
if (m_tool_ordering.empty() || m_tool_ordering.last_extruder() == unsigned(-1))
|
||||
throw Slic3r::SlicingError("The print is empty. The model is not printable with current print settings.");
|
||||
throw Slic3r::SlicingError(L("The print is empty. The model is not printable with current print settings."));
|
||||
|
||||
}
|
||||
this->set_done(psWipeTower);
|
||||
@@ -5407,11 +5412,11 @@ void Print::_make_wipe_tower()
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("wipe tower footprint [%1%,%2%]-[%3%,%4%] leaves printable [%5%,%6%]-[%7%,%8%]") %
|
||||
unscaled(fp.min.x()) % unscaled(fp.min.y()) % unscaled(fp.max.x()) % unscaled(fp.max.y()) %
|
||||
unscaled(pr.min.x()) % unscaled(pr.min.y()) % unscaled(pr.max.x()) % unscaled(pr.max.y());
|
||||
throw Slic3r::SlicingError(L("Prime Tower") + L(" is partially outside the printable area, and it cannot be printed.\n"));
|
||||
throw Slic3r::SlicingError(L("Prime tower is partially outside the printable area, and it cannot be printed.\n"));
|
||||
}
|
||||
// The cutter/purge corner is a physical obstacle — the brim must stay out like the body.
|
||||
if (!intersection(get_bed_excluded_area(m_config), Polygons{footprint}).empty())
|
||||
throw Slic3r::SlicingError(L("Prime Tower") + L(" is too close to an exclusion area, and collisions will be caused.\n"));
|
||||
throw Slic3r::SlicingError(L("Prime tower is too close to an exclusion area, and collisions will be caused.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5526,7 +5531,8 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
|
||||
fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx);
|
||||
}
|
||||
throw Slic3r::RuntimeError(
|
||||
std::string("Failed to process the G-code file ") + file + " from previous 3mf\n");
|
||||
// TRN %1% is a file path.
|
||||
Slic3r::format(L("Failed to process the G-code file %1% from the previous 3MF file."), file) + "\n");
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": process the G-code file %1% successfully")%file.c_str();
|
||||
|
||||
+107
-96
@@ -2438,7 +2438,7 @@ void PrintConfigDef::init_fff_params()
|
||||
|
||||
def = this->add("machine_end_gcode", coString);
|
||||
def->label = L("End G-code");
|
||||
def->tooltip = L("Add end G-Code when finishing the entire print.");
|
||||
def->tooltip = L("Add end G-code when finishing the entire print.");
|
||||
def->multiline = true;
|
||||
def->full_width = true;
|
||||
def->height = 12;
|
||||
@@ -4578,7 +4578,7 @@ void PrintConfigDef::init_fff_params()
|
||||
//def->enum_values.push_back("machinekit");
|
||||
//def->enum_values.push_back("smoothie");
|
||||
//def->enum_values.push_back("no-extrusion");
|
||||
def->enum_labels.push_back("Marlin(legacy)");
|
||||
def->enum_labels.push_back(L("Marlin (legacy)"));
|
||||
def->enum_labels.push_back(L("Klipper"));
|
||||
def->enum_labels.push_back("RepRapFirmware");
|
||||
def->enum_labels.push_back("Repetier");
|
||||
@@ -5301,11 +5301,11 @@ void PrintConfigDef::init_fff_params()
|
||||
(void)L("Maximum speed E");
|
||||
def->category = L("Machine limits");
|
||||
def->readonly = false;
|
||||
def->tooltip = (boost::format("Maximum speed of %1% axis") % axis_upper).str();
|
||||
(void)L("Maximum X speed");
|
||||
(void)L("Maximum Y speed");
|
||||
(void)L("Maximum Z speed");
|
||||
(void)L("Maximum E speed");
|
||||
def->tooltip = (boost::format("Maximum speed of the %1% axis") % axis_upper).str();
|
||||
(void)L("Maximum speed of the X axis");
|
||||
(void)L("Maximum speed of the Y axis");
|
||||
(void)L("Maximum speed of the Z axis");
|
||||
(void)L("Maximum speed of the E axis");
|
||||
def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comSimple;
|
||||
@@ -5919,7 +5919,7 @@ void PrintConfigDef::init_fff_params()
|
||||
|
||||
def = this->add("slicing_pipeline_plugin", coStrings);
|
||||
def->label = L("Slicing Pipeline Plugin");
|
||||
def->tooltip = L("Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, "
|
||||
def->tooltip = L("Python plugins invoked at each slicing pipeline step to read and modify intermediate slicing data, "
|
||||
"including a final G-code post-processing step. Research/experimental.");
|
||||
def->gui_type = ConfigOptionDef::GUIType::plugin_picker;
|
||||
def->plugin_type = "slicing-pipeline";
|
||||
@@ -6943,7 +6943,7 @@ void PrintConfigDef::init_fff_params()
|
||||
// are unchanged; only the gcode emission frame shifts.
|
||||
def = this->add("imex_firmware_managed_zones", coBool);
|
||||
def->label = L("Firmware-managed zones");
|
||||
def->tooltip = L("When enabled, the slicer emits g-code with the primary zone's "
|
||||
def->tooltip = L("When enabled, the slicer emits G-code with the primary zone's "
|
||||
"contents centered on bed origin (0,0). The printer firmware is "
|
||||
"responsible for placing copies/mirrors at each physical zone "
|
||||
"position. Enable only on printers whose firmware applies its own "
|
||||
@@ -7036,7 +7036,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("imex_head_filament_map", coString);
|
||||
def->label = L("IDEX/IQEX head filament map");
|
||||
def->tooltip = L("Per-plate override mapping physical heads to filament slots "
|
||||
"(1-based). Empty means use pem-inversion defaults.");
|
||||
"(1-based). Empty means each head uses the first filament that the "
|
||||
"printer's physical extruder map routes to it.");
|
||||
def->mode = comDevelop;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
@@ -7628,7 +7629,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Printable space");
|
||||
def->tooltip = L("Axis the mesh is rotated about before slicing. This is the belt "
|
||||
"printer's tilt: an isometric (no distortion) rotation that also "
|
||||
"drives bed rendering and support gravity tilt, and that the g-code "
|
||||
"drives bed rendering and support gravity tilt, and that the G-code "
|
||||
"back-transform inverts before the machine-frame shear/scale and remap. "
|
||||
"X is the typical gantry tilt (belt travels along Y).");
|
||||
def->enum_keys_map = &ConfigOptionEnum<BeltRotationAxis>::get_enum_values();
|
||||
@@ -7653,7 +7654,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("belt_frame_tilt_decouple", coBool);
|
||||
def->label = L("Decouple machine-frame tilt");
|
||||
def->category = L("Printable space");
|
||||
def->tooltip = L("Expert override: set the machine-frame (g-code shear/scale) tilt angle "
|
||||
def->tooltip = L("Expert override: set the machine-frame (G-code shear/scale) tilt angle "
|
||||
"independently of the pre-slice rotation angle. When disabled, the "
|
||||
"machine-frame transform is derived from the belt tilt angle, so a single "
|
||||
"angle drives both stages. Enable only to compensate for a machine whose "
|
||||
@@ -8620,7 +8621,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Maximum wall deviation");
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("The maximum deviation allowed when reducing the resolution for the 'Maximum wall resolution' setting. If you increase this, "
|
||||
"the print will be less accurate, but the G-Code will be smaller. 'Maximum wall deviation' limits 'Maximum wall resolution', "
|
||||
"the print will be less accurate, but the G-code will be smaller. 'Maximum wall deviation' limits 'Maximum wall resolution', "
|
||||
"so if the two conflict, 'Maximum wall deviation' takes precedence.");
|
||||
def->sidetext = L("mm"); // millimeters, CIS languages need translation
|
||||
def->mode = comExpert;
|
||||
@@ -9939,7 +9940,8 @@ void PrintConfigDef::handle_legacy_composite(DynamicPrintConfig &config)
|
||||
auto [thumbnails_list, errors] = GCodeThumbnails::make_and_check_thumbnail_list(thumbnails_str, extention);
|
||||
|
||||
if (errors != enum_bitmask<ThumbnailError>()) {
|
||||
std::string error_str = "\n" + Slic3r::format("Invalid value provided for parameter %1%: %2%", "thumbnails", thumbnails_str);
|
||||
// TRN %1% is a parameter name, %2% its value.
|
||||
std::string error_str = "\n" + Slic3r::format(_u8L("Invalid value provided for parameter %1%: %2%"), "thumbnails", thumbnails_str);
|
||||
error_str += GCodeThumbnails::get_error_string(errors);
|
||||
throw BadOptionValueException(error_str);
|
||||
}
|
||||
@@ -12328,42 +12330,42 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
|
||||
std::map<std::string, std::string> error_message;
|
||||
// --layer-height
|
||||
if (cfg.get_abs_value("layer_height") <= 0) {
|
||||
error_message.emplace("layer_height", L("invalid value ") + std::to_string(cfg.get_abs_value("layer_height")));
|
||||
error_message.emplace("layer_height", _u8L("invalid value ") + std::to_string(cfg.get_abs_value("layer_height")));
|
||||
}
|
||||
else if (fabs(fmod(cfg.get_abs_value("layer_height"), SCALING_FACTOR)) > 1e-4) {
|
||||
error_message.emplace("layer_height", L("invalid value ") + std::to_string(cfg.get_abs_value("layer_height")));
|
||||
error_message.emplace("layer_height", _u8L("invalid value ") + std::to_string(cfg.get_abs_value("layer_height")));
|
||||
}
|
||||
|
||||
// --first-layer-height
|
||||
if (cfg.initial_layer_print_height.value <= 0) {
|
||||
error_message.emplace("initial_layer_print_height", L("invalid value ") + std::to_string(cfg.initial_layer_print_height.value));
|
||||
error_message.emplace("initial_layer_print_height", _u8L("invalid value ") + std::to_string(cfg.initial_layer_print_height.value));
|
||||
}
|
||||
|
||||
// --filament-diameter
|
||||
for (double fd : cfg.filament_diameter.values)
|
||||
if (fd < 1) {
|
||||
error_message.emplace("filament_diameter", L("invalid value ") + cfg.filament_diameter.serialize());
|
||||
error_message.emplace("filament_diameter", _u8L("invalid value ") + cfg.filament_diameter.serialize());
|
||||
break;
|
||||
}
|
||||
|
||||
// --nozzle-diameter
|
||||
for (double nd : cfg.nozzle_diameter.values)
|
||||
if (nd < 0.005) {
|
||||
error_message.emplace("nozzle_diameter", L("invalid value ") + cfg.nozzle_diameter.serialize());
|
||||
error_message.emplace("nozzle_diameter", _u8L("invalid value ") + cfg.nozzle_diameter.serialize());
|
||||
break;
|
||||
}
|
||||
|
||||
// --perimeters
|
||||
if (cfg.wall_loops.value < 0) {
|
||||
error_message.emplace("wall_loops", L("invalid value ") + std::to_string(cfg.wall_loops.value));
|
||||
error_message.emplace("wall_loops", _u8L("invalid value ") + std::to_string(cfg.wall_loops.value));
|
||||
}
|
||||
|
||||
// --solid-layers
|
||||
if (cfg.top_shell_layers < 0) {
|
||||
error_message.emplace("top_shell_layers", L("invalid value ") + std::to_string(cfg.top_shell_layers));
|
||||
error_message.emplace("top_shell_layers", _u8L("invalid value ") + std::to_string(cfg.top_shell_layers));
|
||||
}
|
||||
if (cfg.bottom_shell_layers < 0) {
|
||||
error_message.emplace("bottom_shell_layers", L("invalid value ") + std::to_string(cfg.bottom_shell_layers));
|
||||
error_message.emplace("bottom_shell_layers", _u8L("invalid value ") + std::to_string(cfg.bottom_shell_layers));
|
||||
}
|
||||
|
||||
if (cfg.use_firmware_retraction.value &&
|
||||
@@ -12384,61 +12386,61 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
|
||||
|
||||
// --gcode-flavor
|
||||
if (! print_config_def.get("gcode_flavor")->has_enum_value(cfg.gcode_flavor.serialize())) {
|
||||
error_message.emplace("gcode_flavor", L("invalid value ") + cfg.gcode_flavor.serialize());
|
||||
error_message.emplace("gcode_flavor", _u8L("invalid value ") + cfg.gcode_flavor.serialize());
|
||||
}
|
||||
|
||||
// --fill-pattern
|
||||
if (! print_config_def.get("sparse_infill_pattern")->has_enum_value(cfg.sparse_infill_pattern.serialize())) {
|
||||
error_message.emplace("sparse_infill_pattern", L("invalid value ") + cfg.sparse_infill_pattern.serialize());
|
||||
error_message.emplace("sparse_infill_pattern", _u8L("invalid value ") + cfg.sparse_infill_pattern.serialize());
|
||||
}
|
||||
|
||||
// --top-fill-pattern
|
||||
if (! print_config_def.get("top_surface_pattern")->has_enum_value(cfg.top_surface_pattern.serialize())) {
|
||||
error_message.emplace("top_surface_pattern", L("invalid value ") + cfg.top_surface_pattern.serialize());
|
||||
error_message.emplace("top_surface_pattern", _u8L("invalid value ") + cfg.top_surface_pattern.serialize());
|
||||
}
|
||||
|
||||
// --bottom-fill-pattern
|
||||
if (! print_config_def.get("bottom_surface_pattern")->has_enum_value(cfg.bottom_surface_pattern.serialize())) {
|
||||
error_message.emplace("bottom_surface_pattern", L("invalid value ") + cfg.bottom_surface_pattern.serialize());
|
||||
error_message.emplace("bottom_surface_pattern", _u8L("invalid value ") + cfg.bottom_surface_pattern.serialize());
|
||||
}
|
||||
|
||||
// --soild-fill-pattern
|
||||
if (!print_config_def.get("internal_solid_infill_pattern")->has_enum_value(cfg.internal_solid_infill_pattern.serialize())) {
|
||||
error_message.emplace("internal_solid_infill_pattern", L("invalid value ") + cfg.internal_solid_infill_pattern.serialize());
|
||||
error_message.emplace("internal_solid_infill_pattern", _u8L("invalid value ") + cfg.internal_solid_infill_pattern.serialize());
|
||||
}
|
||||
|
||||
// --skirt-height
|
||||
if (cfg.skirt_height < 0) {
|
||||
error_message.emplace("skirt_height", L("invalid value ") + std::to_string(cfg.skirt_height));
|
||||
error_message.emplace("skirt_height", _u8L("invalid value ") + std::to_string(cfg.skirt_height));
|
||||
}
|
||||
|
||||
// --bridge-flow-ratio
|
||||
if (cfg.bridge_flow <= 0) {
|
||||
error_message.emplace("bridge_flow", L("invalid value ") + std::to_string(cfg.bridge_flow));
|
||||
error_message.emplace("bridge_flow", _u8L("invalid value ") + std::to_string(cfg.bridge_flow));
|
||||
}
|
||||
|
||||
// --internal-bridge-flow-ratio
|
||||
if (cfg.internal_bridge_flow <= 0) {
|
||||
error_message.emplace("internal_bridge_flow", L("invalid value ") + std::to_string(cfg.internal_bridge_flow));
|
||||
error_message.emplace("internal_bridge_flow", _u8L("invalid value ") + std::to_string(cfg.internal_bridge_flow));
|
||||
}
|
||||
|
||||
// extruder clearance
|
||||
if (cfg.extruder_clearance_radius <= 0) {
|
||||
error_message.emplace("extruder_clearance_radius", L("invalid value ") + std::to_string(cfg.extruder_clearance_radius));
|
||||
error_message.emplace("extruder_clearance_radius", _u8L("invalid value ") + std::to_string(cfg.extruder_clearance_radius));
|
||||
}
|
||||
if (cfg.extruder_clearance_height_to_rod <= 0) {
|
||||
error_message.emplace("extruder_clearance_height_to_rod", L("invalid value ") + std::to_string(cfg.extruder_clearance_height_to_rod));
|
||||
error_message.emplace("extruder_clearance_height_to_rod", _u8L("invalid value ") + std::to_string(cfg.extruder_clearance_height_to_rod));
|
||||
}
|
||||
if (cfg.extruder_clearance_height_to_lid <= 0) {
|
||||
error_message.emplace("extruder_clearance_height_to_lid", L("invalid value ") + std::to_string(cfg.extruder_clearance_height_to_lid));
|
||||
error_message.emplace("extruder_clearance_height_to_lid", _u8L("invalid value ") + std::to_string(cfg.extruder_clearance_height_to_lid));
|
||||
}
|
||||
if (cfg.nozzle_height <= 0)
|
||||
error_message.emplace("nozzle_height", L("invalid value ") + std::to_string(cfg.nozzle_height));
|
||||
error_message.emplace("nozzle_height", _u8L("invalid value ") + std::to_string(cfg.nozzle_height));
|
||||
|
||||
// --extrusion-multiplier
|
||||
for (double em : cfg.filament_flow_ratio.values)
|
||||
if (em <= 0) {
|
||||
error_message.emplace("filament_flow_ratio", L("invalid value ") + cfg.filament_flow_ratio.serialize());
|
||||
error_message.emplace("filament_flow_ratio", _u8L("invalid value ") + cfg.filament_flow_ratio.serialize());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12448,27 +12450,27 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
|
||||
// Note that we might want to have more than one perimeter on the bottom
|
||||
// solid layers.
|
||||
if (cfg.wall_loops != 1) {
|
||||
error_message.emplace("wall_loops", L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.wall_loops));
|
||||
error_message.emplace("wall_loops", _u8L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.wall_loops));
|
||||
//return "Can't make more than one perimeter when spiral vase mode is enabled";
|
||||
//return "Can't make less than one perimeter when spiral vase mode is enabled";
|
||||
}
|
||||
|
||||
if (cfg.sparse_infill_density > 0) {
|
||||
error_message.emplace("sparse_infill_density", L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.sparse_infill_density));
|
||||
error_message.emplace("sparse_infill_density", _u8L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.sparse_infill_density));
|
||||
//return "Spiral vase mode can only print hollow objects, so you need to set Fill density to 0";
|
||||
}
|
||||
|
||||
if (cfg.top_shell_layers > 0) {
|
||||
error_message.emplace("top_shell_layers", L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.top_shell_layers));
|
||||
error_message.emplace("top_shell_layers", _u8L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.top_shell_layers));
|
||||
//return "Spiral vase mode is not compatible with top solid layers";
|
||||
}
|
||||
|
||||
if (cfg.enable_support ) {
|
||||
error_message.emplace("enable_support", L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.enable_support));
|
||||
error_message.emplace("enable_support", _u8L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.enable_support));
|
||||
//return "Spiral vase mode is not compatible with support";
|
||||
}
|
||||
if (cfg.enforce_support_layers > 0) {
|
||||
error_message.emplace("enforce_support_layers", L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.enforce_support_layers));
|
||||
error_message.emplace("enforce_support_layers", _u8L("Invalid value when spiral vase mode is enabled: ") + std::to_string(cfg.enforce_support_layers));
|
||||
//return "Spiral vase mode is not compatible with support";
|
||||
}
|
||||
}
|
||||
@@ -12499,9 +12501,9 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
|
||||
double allowed_max = (key == "bridge_line_width") ? min_nozzle_diameter : MAX_LINE_WIDTH_MULTIPLIER * max_nozzle_diameter;
|
||||
if (abs_width > allowed_max) {
|
||||
if (key == "bridge_line_width")
|
||||
error_message.emplace(key, L("Bridge line width must not exceed nozzle diameter: ") + std::to_string(abs_width));
|
||||
error_message.emplace(key, _u8L("Bridge line width must not exceed nozzle diameter: ") + std::to_string(abs_width));
|
||||
else
|
||||
error_message.emplace(key, L("too large line width ") + std::to_string(abs_width));
|
||||
error_message.emplace(key, _u8L("too large line width ") + std::to_string(abs_width));
|
||||
//return std::string("Too Large line width: ") + key;
|
||||
}
|
||||
}
|
||||
@@ -12548,7 +12550,8 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
|
||||
}
|
||||
if (out_of_range) {
|
||||
if (error_message.find(opt_key) == error_message.end())
|
||||
error_message.emplace(opt_key, opt->serialize() + L(" not in range ") +"[" + std::to_string(optdef->min) + "," + std::to_string(optdef->max) + "]");
|
||||
// TRN %1% is the current value, %2% and %3% the lowest and highest allowed values.
|
||||
error_message.emplace(opt_key, Slic3r::format(_u8L("%1% not in range [%2%, %3%]"), opt->serialize(), optdef->min, optdef->max));
|
||||
//return std::string("Value out of range: " + opt_key);
|
||||
}
|
||||
}
|
||||
@@ -12606,7 +12609,7 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
// Actions:
|
||||
/*def = this->add("export_obj", coBool);
|
||||
def->label = L("Export OBJ");
|
||||
def->tooltip = L("Export the model(s) as OBJ.");
|
||||
def->tooltip = L("Export the models as OBJ.");
|
||||
def->set_default_value(new ConfigOptionBool(false));*/
|
||||
|
||||
/*
|
||||
@@ -12642,7 +12645,7 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
|
||||
/*def = this->add("export_amf", coBool);
|
||||
def->label = L("Export AMF");
|
||||
def->tooltip = L("Export the model(s) as AMF.");
|
||||
def->tooltip = L("Export the models as AMF.");
|
||||
def->set_default_value(new ConfigOptionBool(false));*/
|
||||
|
||||
def = this->add("export_stl", coBool);
|
||||
@@ -12926,7 +12929,7 @@ CLITransformConfigDef::CLITransformConfigDef()
|
||||
|
||||
/*def = this->add("split", coBool);
|
||||
def->label = L("Split");
|
||||
def->tooltip = L("Detect unconnected parts in the given model(s) and split them into separate objects.");
|
||||
def->tooltip = L("Detect unconnected parts in the given models and split them into separate objects.");
|
||||
|
||||
def = this->add("scale_to_fit", coPoint3);
|
||||
def->label = L("Scale to Fit");
|
||||
@@ -13234,12 +13237,12 @@ OtherSlicingStatesConfigDef::OtherSlicingStatesConfigDef()
|
||||
def->label = L("Has single extruder MM priming");
|
||||
def->tooltip = L("Are the extra multi-material priming regions used in this print?");
|
||||
|
||||
new_def("initial_no_support_extruder", coInt, "Initial no support extruder", "Zero-based index of the first extruder used for printing without support. Same as initial_no_support_tool.");
|
||||
new_def("in_head_wrap_detect_zone", coBool, "In head wrap detect zone", "Indicates if the first layer overlaps with the head wrap zone.");
|
||||
new_def("curr_bed_type", coString, "Current bed type", "Name of the currently selected bed plate type (e.g. 'Textured PEI Plate', 'Smooth High Temp Plate').");
|
||||
new_def("imex_mode", coString, "IDEX/IQEX active mode", "Name of the active IDEX/IQEX parallel print mode for this plate (e.g. 'primary', 'mirror', 'copy'). Empty string if IDEX/IQEX is not enabled.");
|
||||
new_def("imex_mode_index", coInt, "IDEX/IQEX active mode index", "Zero-based index of the active IDEX/IQEX parallel print mode within imex_mode_names.");
|
||||
new_def("imex_mode_gcode", coString, "IDEX/IQEX active mode G-code", "The raw mode G-code template for the active IDEX/IQEX parallel print mode, after placeholder evaluation. Globals defined here flow into machine_start_gcode.");
|
||||
new_def("initial_no_support_extruder", coInt, L("Initial no support extruder"), L("Zero-based index of the first extruder used for printing without support. Same as initial_no_support_tool."));
|
||||
new_def("in_head_wrap_detect_zone", coBool, L("In head wrap detect zone"), L("Indicates if the first layer overlaps with the head wrap zone."));
|
||||
new_def("curr_bed_type", coString, L("Current bed type"), L("Name of the currently selected bed plate type (e.g. 'Textured PEI Plate', 'Smooth High Temp Plate')."));
|
||||
new_def("imex_mode", coString, L("IDEX/IQEX active mode"), L("Name of the active IDEX/IQEX parallel print mode for this plate (e.g. 'primary', 'mirror', 'copy'). Empty string if IDEX/IQEX is not enabled."));
|
||||
new_def("imex_mode_index", coInt, L("IDEX/IQEX active mode index"), L("Zero-based index of the active IDEX/IQEX parallel print mode within imex_mode_names."));
|
||||
new_def("imex_mode_gcode", coString, L("IDEX/IQEX active mode G-code"), L("The raw mode G-code template for the active IDEX/IQEX parallel print mode, after placeholder evaluation. Globals defined here flow into machine_start_gcode."));
|
||||
}
|
||||
|
||||
PrintStatisticsConfigDef::PrintStatisticsConfigDef()
|
||||
@@ -13357,8 +13360,8 @@ ObjectsInfoConfigDef::ObjectsInfoConfigDef()
|
||||
def->label = L("Input filename without extension");
|
||||
def->tooltip = L("Source filename of the first object, without extension.");
|
||||
|
||||
new_def("input_filename", coString, "Full input filename", "Source filename of the first object.");
|
||||
new_def("plate_name", coString, "Plate name", "Name of the plate sliced.");
|
||||
new_def("input_filename", coString, L("Full input filename"), L("Source filename of the first object."));
|
||||
new_def("plate_name", coString, L("Plate name"), L("Name of the plate sliced."));
|
||||
}
|
||||
|
||||
DimensionsConfigDef::DimensionsConfigDef()
|
||||
@@ -13397,22 +13400,22 @@ DimensionsConfigDef::DimensionsConfigDef()
|
||||
def->label = L("Size of the print bed bounding box");
|
||||
def->tooltip = bb_size_tooltip;
|
||||
|
||||
new_def("first_layer_center_no_wipe_tower", coFloats, "First layer center without wipe tower", point_tooltip);
|
||||
new_def("first_layer_height", coFloat, "First layer height", "Height of the first layer.");
|
||||
new_def("first_layer_center_no_wipe_tower", coFloats, L("First layer center without wipe tower"), point_tooltip);
|
||||
new_def("first_layer_height", coFloat, L("First layer height"), L("Height of the first layer."));
|
||||
}
|
||||
|
||||
TemperaturesConfigDef::TemperaturesConfigDef()
|
||||
{
|
||||
ConfigOptionDef* def;
|
||||
|
||||
new_def("bed_temperature", coInts, "Bed temperature", "Vector of bed temperatures for each extruder/filament.")
|
||||
new_def("bed_temperature_initial_layer", coInts, "First layer bed temperature", "Vector of first layer bed temperatures for each extruder/filament. Provides the same value as first_layer_bed_temperature.")
|
||||
new_def("bed_temperature_initial_layer_single", coInt, "First layer bed temperature (initial extruder)", "First layer bed temperature for the initial extruder. Same as bed_temperature_initial_layer[initial_extruder]")
|
||||
new_def("chamber_temperature", coInts, "Chamber temperature", "Vector of chamber temperatures for each extruder/filament.")
|
||||
new_def("chamber_minimal_temperature", coInts, "Chamber minimal temperature", "Vector of minimal chamber temperatures for each extruder/filament.")
|
||||
new_def("overall_chamber_temperature", coInt, "Overall chamber temperature", "Overall chamber temperature. This value is the maximum chamber temperature of any extruder/filament used.")
|
||||
new_def("first_layer_bed_temperature", coInts, "First layer bed temperature", "Vector of first layer bed temperatures for each extruder/filament. Provides the same value as bed_temperature_initial_layer.")
|
||||
new_def("first_layer_temperature", coInts, "First layer temperature", "Vector of first layer temperatures for each extruder/filament.")
|
||||
new_def("bed_temperature", coInts, L("Bed temperature"), L("Vector of bed temperatures for each extruder/filament."))
|
||||
new_def("bed_temperature_initial_layer", coInts, L("First layer bed temperature"), L("Vector of first layer bed temperatures for each extruder/filament. Provides the same value as first_layer_bed_temperature."))
|
||||
new_def("bed_temperature_initial_layer_single", coInt, L("First layer bed temperature (initial extruder)"), L("First layer bed temperature for the initial extruder. Same as bed_temperature_initial_layer[initial_extruder]"))
|
||||
new_def("chamber_temperature", coInts, L("Chamber temperature"), L("Vector of chamber temperatures for each extruder/filament."))
|
||||
new_def("chamber_minimal_temperature", coInts, L("Chamber minimal temperature"), L("Vector of minimal chamber temperatures for each extruder/filament."))
|
||||
new_def("overall_chamber_temperature", coInt, L("Overall chamber temperature"), L("Overall chamber temperature. This value is the maximum chamber temperature of any extruder/filament used."))
|
||||
new_def("first_layer_bed_temperature", coInts, L("First layer bed temperature"), L("Vector of first layer bed temperatures for each extruder/filament. Provides the same value as bed_temperature_initial_layer."))
|
||||
new_def("first_layer_temperature", coInts, L("First layer temperature"), L("Vector of first layer temperatures for each extruder/filament."))
|
||||
}
|
||||
|
||||
|
||||
@@ -13519,42 +13522,50 @@ CustomGcodeSpecificConfigDef::CustomGcodeSpecificConfigDef()
|
||||
def->tooltip = L("The current extruder ID. The same as current_extruder.");
|
||||
|
||||
// change_filament_gcode
|
||||
new_def("previous_extruder", coInt, "Previous extruder", "Index of the extruder that is being unloaded. The index is zero based (first extruder has index 0).");
|
||||
new_def("next_extruder", coInt, "Next extruder", "Index of the extruder that is being loaded. The index is zero based (first extruder has index 0).");
|
||||
new_def("relative_e_axis", coBool, "Relative e-axis", "Indicates if relative positioning is being used.");
|
||||
new_def("toolchange_count", coInt, "Toolchange count", "The number of toolchanges throught the print.");
|
||||
new_def("previous_extruder", coInt, L("Previous extruder"), L("Index of the extruder that is being unloaded. The index is zero based (first extruder has index 0)."));
|
||||
new_def("next_extruder", coInt, L("Next extruder"), L("Index of the extruder that is being loaded. The index is zero based (first extruder has index 0)."));
|
||||
new_def("relative_e_axis", coBool, L("Relative e-axis"), L("Indicates if relative positioning is being used."));
|
||||
new_def("toolchange_count", coInt, L("Toolchange count"), L("The number of toolchanges throughout the print."));
|
||||
new_def("fan_speed", coNone, "", ""); //Option is no longer used and is zeroed by placeholder parser for compatability
|
||||
new_def("old_retract_length", coFloat, "Old retract length", "The retraction length of the previous filament.");
|
||||
new_def("new_retract_length", coFloat, "New retract length", "The retraction lenght of the new filament.");
|
||||
new_def("old_retract_length_toolchange", coFloat, "Old retract length toolchange", "The toolchange retraction length of the previous filament.");
|
||||
new_def("new_retract_length_toolchange", coFloat, "New retract length toolchange", "The toolchange retraction length of the new filament.");
|
||||
new_def("old_filament_temp", coInt, "Old filament temp", "The old filament temp.");
|
||||
new_def("new_filament_temp", coInt, "New filament temp", "The new filament temp.");
|
||||
new_def("x_after_toolchange", coFloat, "X after toolchange", "The X pos after toolchange.");
|
||||
new_def("y_after_toolchange", coFloat, "Y after toolchange", "The Y pos after toolchange.");
|
||||
new_def("z_after_toolchange", coFloat, "Z after toolchange", "The Z pos after toolchange.");
|
||||
new_def("first_flush_volume", coFloat, "First flush volume", "The first flush volume.");
|
||||
new_def("second_flush_volume", coFloat, "Second flush volume", "The second flush volume.");
|
||||
new_def("old_filament_e_feedrate", coInt, "Old filament e feedrate", "The old filament extruder feedrate.");
|
||||
new_def("new_filament_e_feedrate", coInt, "New filament e feedrate", "The new filament extruder feedrate.");
|
||||
new_def("travel_point_1_x", coFloat, "Travel point 1 X", "The travel point 1 X.");
|
||||
new_def("travel_point_1_y", coFloat, "Travel point 1 Y", "The travel point 1 Y.");
|
||||
new_def("travel_point_2_x", coFloat, "Travel point 2 X", "The travel point 2 X.");
|
||||
new_def("travel_point_2_y", coFloat, "Travel point 2 Y", "The travel point 2 Y.");
|
||||
new_def("travel_point_3_x", coFloat, "Travel point 3 X", "The travel point 3 X.");
|
||||
new_def("travel_point_3_y", coFloat, "Travel point 3 Y", "The travel point 3 Y.");
|
||||
new_def("flush_length_1", coFloat, "Flush Length 1", "The first flush length.");
|
||||
new_def("flush_length_2", coFloat, "Flush Length 2", "The second flush length.");
|
||||
new_def("flush_length_3", coFloat, "Flush Length 3", "The third flush length.");
|
||||
new_def("flush_length_4", coFloat, "Flush Length 4", "The fourth flush length.");
|
||||
new_def("old_retract_length", coFloat, L("Old retract length"), L("The retraction length of the previous filament."));
|
||||
new_def("new_retract_length", coFloat, L("New retract length"), L("The retraction length of the new filament."));
|
||||
new_def("old_retract_length_toolchange", coFloat, L("Old retract length toolchange"), L("The toolchange retraction length of the previous filament."));
|
||||
new_def("new_retract_length_toolchange", coFloat, L("New retract length toolchange"), L("The toolchange retraction length of the new filament."));
|
||||
new_def("old_filament_temp", coInt, L("Old filament temp"), L("The old filament temp."));
|
||||
new_def("new_filament_temp", coInt, L("New filament temp"), L("The new filament temp."));
|
||||
new_def("x_after_toolchange", coFloat, L("X after toolchange"), L("The X pos after toolchange."));
|
||||
new_def("y_after_toolchange", coFloat, L("Y after toolchange"), L("The Y pos after toolchange."));
|
||||
new_def("z_after_toolchange", coFloat, L("Z after toolchange"), L("The Z pos after toolchange."));
|
||||
new_def("first_flush_volume", coFloat, L("First flush volume"), L("The first flush volume."));
|
||||
new_def("second_flush_volume", coFloat, L("Second flush volume"), L("The second flush volume."));
|
||||
new_def("old_filament_e_feedrate", coInt, L("Old filament e feedrate"), L("The old filament extruder feedrate."));
|
||||
new_def("new_filament_e_feedrate", coInt, L("New filament e feedrate"), L("The new filament extruder feedrate."));
|
||||
new_def("travel_point_1_x", coFloat, L("Travel point 1 X"), L("The travel point 1 X."));
|
||||
new_def("travel_point_1_y", coFloat, L("Travel point 1 Y"), L("The travel point 1 Y."));
|
||||
new_def("travel_point_2_x", coFloat, L("Travel point 2 X"), L("The travel point 2 X."));
|
||||
new_def("travel_point_2_y", coFloat, L("Travel point 2 Y"), L("The travel point 2 Y."));
|
||||
new_def("travel_point_3_x", coFloat, L("Travel point 3 X"), L("The travel point 3 X."));
|
||||
new_def("travel_point_3_y", coFloat, L("Travel point 3 Y"), L("The travel point 3 Y."));
|
||||
new_def("flush_length_1", coFloat, L("Flush Length 1"), L("The first flush length."));
|
||||
new_def("flush_length_2", coFloat, L("Flush Length 2"), L("The second flush length."));
|
||||
new_def("flush_length_3", coFloat, L("Flush Length 3"), L("The third flush length."));
|
||||
new_def("flush_length_4", coFloat, L("Flush Length 4"), L("The fourth flush length."));
|
||||
|
||||
// change_extrusion_role_gcode
|
||||
std::string extrusion_role_types = "Possible Values:\n[\"Perimeter\", \"ExternalPerimeter\", "
|
||||
"\"OverhangPerimeter\", \"InternalInfill\", \"SolidInfill\", \"TopSolidInfill\", \"BottomSurface\", \"BridgeInfill\", \"GapFill\", \"Ironing\", "
|
||||
"\"Skirt\", \"Brim\", \"SupportMaterial\", \"SupportMaterialInterface\", \"SupportTransition\", \"WipeTower\", \"Mixed\"]";
|
||||
// The whole tooltip is one literal so that the GUI can look it up in the catalog.
|
||||
def = this->add("extrusion_role", coString);
|
||||
def->label = L("Extrusion role");
|
||||
// TRN The quoted values are G-code identifiers; keep them in English.
|
||||
def->tooltip = L("The new extrusion role/type that is going to be used\nPossible values:\n[\"Perimeter\", \"ExternalPerimeter\", "
|
||||
"\"OverhangPerimeter\", \"InternalInfill\", \"SolidInfill\", \"TopSolidInfill\", \"BottomSurface\", \"BridgeInfill\", \"GapFill\", \"Ironing\", "
|
||||
"\"Skirt\", \"Brim\", \"SupportMaterial\", \"SupportMaterialInterface\", \"SupportTransition\", \"WipeTower\", \"Mixed\"]");
|
||||
|
||||
new_def("extrusion_role", coString, "Extrusion role", "The new extrusion role/type that is going to be used\n" + extrusion_role_types);
|
||||
new_def("last_extrusion_role", coString, "Last extrusion role", "The previously used extrusion role/type\nPossible Values:\n" + extrusion_role_types);
|
||||
def = this->add("last_extrusion_role", coString);
|
||||
def->label = L("Last extrusion role");
|
||||
// TRN The quoted values are G-code identifiers; keep them in English.
|
||||
def->tooltip = L("The previously used extrusion role/type\nPossible values:\n[\"Perimeter\", \"ExternalPerimeter\", "
|
||||
"\"OverhangPerimeter\", \"InternalInfill\", \"SolidInfill\", \"TopSolidInfill\", \"BottomSurface\", \"BridgeInfill\", \"GapFill\", \"Ironing\", "
|
||||
"\"Skirt\", \"Brim\", \"SupportMaterial\", \"SupportMaterialInterface\", \"SupportTransition\", \"WipeTower\", \"Mixed\"]");
|
||||
}
|
||||
|
||||
const CustomGcodeSpecificConfigDef custom_gcode_specific_config_def;
|
||||
|
||||
@@ -885,7 +885,8 @@ void PrintObject::contour_z()
|
||||
|
||||
std::scoped_lock lock(mtx);
|
||||
completed++;
|
||||
std::string msg = (boost::format("Z contoured layer %d/%d (%d%%)") % (completed) % m_layers.size() % int(double(completed) / m_layers.size() * 100)).str();
|
||||
// TRN Slicing status: layers done, total layers, percentage done.
|
||||
std::string msg = (boost::format(L("Z contoured layer %d/%d (%d%%)")) % (completed) % m_layers.size() % int(double(completed) / m_layers.size() * 100)).str();
|
||||
m_print->set_status(40, msg);
|
||||
}
|
||||
}
|
||||
@@ -958,12 +959,11 @@ void PrintObject::generate_support_material(bool with_belt_brim)
|
||||
BOOST_LOG_TRIVIAL(info) << std::fixed << std::setprecision(0) << "is_support_necessary takes " << duration << " secs.";
|
||||
|
||||
if (sntype != NoNeedSupp) {
|
||||
std::map<SupportNecessaryType, std::string> reasons = {
|
||||
{SharpTail,L("floating regions")},
|
||||
{Cantilever,L("floating cantilever")},
|
||||
{LargeOverhang,L("large overhangs")} };
|
||||
std::string warning_message = Slic3r::format(L("It seems object %s has %s. Please re-orient the object or enable support generation."),
|
||||
this->model_object()->name, reasons[sntype]);
|
||||
std::map<SupportNecessaryType, std::string> messages = {
|
||||
{SharpTail,L("It seems object %1% has floating regions. Please re-orient the object or enable support generation.")},
|
||||
{Cantilever,L("It seems object %1% has a floating cantilever. Please re-orient the object or enable support generation.")},
|
||||
{LargeOverhang,L("It seems object %1% has large overhangs. Please re-orient the object or enable support generation.")} };
|
||||
std::string warning_message = Slic3r::format(messages[sntype], this->model_object()->name);
|
||||
this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, warning_message, PrintStateBase::SlicingNeedSupportOn);
|
||||
}
|
||||
|
||||
|
||||
@@ -956,7 +956,7 @@ void PrintObject::slice()
|
||||
}
|
||||
});
|
||||
if (m_layers.empty())
|
||||
throw Slic3r::SlicingError(L("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n"));
|
||||
throw Slic3r::SlicingError(L("No layers were detected. You might want to repair the model or check its size or thickness and retry.\n"));
|
||||
|
||||
// Belt printer: offset all layer Z values so objects at different positions
|
||||
// along the belt print at different heights on the tilted belt. This is a
|
||||
|
||||
@@ -263,7 +263,7 @@ std::string MZ_Archive::get_errorstr(mz_zip_error mz_err)
|
||||
break;
|
||||
}
|
||||
|
||||
return "unknown error";
|
||||
return L("unknown error");
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -1948,7 +1948,7 @@ void copy_directory_recursively(const boost::filesystem::path& source,
|
||||
if (cfr != CopyFileResult::SUCCESS) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Copying failed(" << cfr << "): " << error_message;
|
||||
throw Slic3r::CriticalException(Slic3r::format(
|
||||
("Copying directory %1% to %2% failed: %3%"),
|
||||
_u8L("Copying directory %1% to %2% failed: %3%"),
|
||||
source, target, error_message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,7 +513,7 @@ wxBoxSizer* AMSDryCtrWin::create_normal_state_panel(wxPanel* parent)
|
||||
m_time_input->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
|
||||
m_time_input->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK));
|
||||
|
||||
Label* time_unit_label = new Label(parent, "H");
|
||||
Label* time_unit_label = new Label(parent, _L_CONTEXT("H", "Hours unit"));
|
||||
time_unit_label->SetForegroundColour(*wxBLACK);
|
||||
time_sizer->Add(m_time_input, 1, wxRIGHT, FromDIP(1));
|
||||
time_sizer->Add(time_unit_label, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
@@ -974,12 +974,12 @@ void AuxiliaryPanel::on_import_file(wxCommandEvent &event)
|
||||
|
||||
if (file_model == s_default_folders[MODEL_PICTURE]) {
|
||||
//wildcard = wxT("JPEG files (*.jpeg)|*.jpeg|BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif|PNG files (*.png)|*.png|JPG files (*.jpg)|*.jpg");
|
||||
wildcard = wxT("files (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp");
|
||||
wildcard = _L("Image files") + " (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp";
|
||||
}
|
||||
|
||||
if (file_model == s_default_folders[OTHERS]) { wildcard = wxT("TXT files (*.txt)|*.txt"); }
|
||||
if (file_model == s_default_folders[BILL_OF_MATERIALS]){ wildcard = wxT("EXCEL files (*.xls)|*.xls|EXCEL files (*.xlsx)|*.xlsx|PDF files (*.pdf)|*.pdf"); }
|
||||
if (file_model == s_default_folders[ASSEMBLY_GUIDE]) { wildcard = wxT("PDF files (*.pdf)|*.pdf"); }
|
||||
if (file_model == s_default_folders[OTHERS]) { wildcard = _L("TXT files") + " (*.txt)|*.txt"; }
|
||||
if (file_model == s_default_folders[BILL_OF_MATERIALS]){ wildcard = _L("EXCEL files") + " (*.xls)|*.xls|" + _L("EXCEL files") + " (*.xlsx)|*.xlsx|" + _L("PDF files") + " (*.pdf)|*.pdf"; }
|
||||
if (file_model == s_default_folders[ASSEMBLY_GUIDE]) { wildcard = _L("PDF files") + " (*.pdf)|*.pdf"; }
|
||||
|
||||
wxFileDialog dialog(this, _L("Choose files"), wxEmptyString, wxEmptyString, wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);
|
||||
if (dialog.ShowModal() == wxID_OK) {
|
||||
|
||||
@@ -122,7 +122,7 @@ std::pair<std::string, std::vector<size_t>> SlicingProcessCompletedEvent::format
|
||||
} catch (std::exception& ex) {
|
||||
error = ex.what();
|
||||
} catch (...) {
|
||||
error = "Unknown C++ exception.";
|
||||
error = _u8L("Unknown C++ exception.");
|
||||
}
|
||||
return std::make_pair(std::move(error), std::vector<size_t>{monospace});
|
||||
}
|
||||
|
||||
@@ -931,7 +931,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
});
|
||||
|
||||
feat_dropdown("plane", "design_plane", _L("Datum / Curve (plane / axis / coord sys / helix / project)"), {
|
||||
{"design_plane", _L("Plane"), _L("Reference plane (offset / tilt / midplane / tangent / two edges / coincident)"),
|
||||
{"design_plane", _L_CONTEXT("Plane", "Design"), _L("Reference plane (offset / tilt / midplane / tangent / two edges / coincident)"),
|
||||
[this] {
|
||||
populate_plane_choices(m_plane_base);
|
||||
reset_plane_refs();
|
||||
@@ -1011,7 +1011,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
}
|
||||
open_tool(Tool::Transform);
|
||||
}, SHIFT('Y')},
|
||||
{"design_mirror", _L("Mirror"), _L("Reflect a body about a plane"),
|
||||
{"design_mirror", _L_CONTEXT("Mirror", "Design"), _L("Reflect a body about a plane"),
|
||||
[this] {
|
||||
if (m_doc.bodies.empty()) {
|
||||
set_status(StatusKind::Error, _L("Mirror needs a body — add or import one first"));
|
||||
@@ -1143,7 +1143,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
|
||||
// Hole / Thread — drilling into a solid (both face-aware)
|
||||
feat_dropdown("hole", "design_hole", _L("Hole / thread"), {
|
||||
{"design_hole", _L("Hole"), _L("Drill a hole, centered on a picked face or placed on a plane"),
|
||||
{"design_hole", _L_CONTEXT("Hole", "Design"), _L("Drill a hole, centered on a picked face or placed on a plane"),
|
||||
[this] {
|
||||
// #2: drill on the picked solid face, centred on it (origin = face centroid,
|
||||
// normal = inward). Otherwise fall back to the plane dropdown. m_hole_x/y then
|
||||
@@ -1344,7 +1344,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
_L("Click 2 points or a line / circle / arc to place a dimension"));
|
||||
// (separator dropped: the group it divided is now reached from the offer)
|
||||
dropdown("design_line", _L("Line / polyline"), {
|
||||
{"design_line", DesignSketchTool::Mode::Line, _L("Line"), _L("Click start, then end — then set the exact length")},
|
||||
{"design_line", DesignSketchTool::Mode::Line, _L_CONTEXT("Line", "Design"), _L("Click start, then end — then set the exact length")},
|
||||
{"design_polyline", DesignSketchTool::Mode::Polyline, _L("Polyline"), _L("Click points; click the first point to close the loop, right-click or Enter to end the chain")} });
|
||||
dropdown("design_rect", _L("Rectangle"), {
|
||||
{"design_rect", DesignSketchTool::Mode::CornerRect, _L("Corner rectangle"), _L("Click two opposite corners")},
|
||||
@@ -1407,7 +1407,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
{"design_chamfer", DesignSketchTool::Mode::Chamfer, _L("Chamfer"), _L("Pick two lines, then drag the arrow or click the distance to set it")} });
|
||||
skbtn("design_offset", DesignSketchTool::Mode::Offset, _L("Offset"),
|
||||
_L("Pick an entity, then drag the arrow or click the distance; click empty to apply"));
|
||||
skbtn("design_mirror", DesignSketchTool::Mode::Mirror, _L("Mirror"),
|
||||
skbtn("design_mirror", DesignSketchTool::Mode::Mirror, _L_CONTEXT("Mirror", "Design"),
|
||||
_L("Pick a mirror-axis line, then the entities to mirror; click empty to apply"));
|
||||
// Trim / Extend scissors — standalone sketch tools (NOT inside Constrain): click a
|
||||
// segment to cut it back to / out to its nearest intersection. One cut per click.
|
||||
@@ -1438,9 +1438,12 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
auto arm_polygon = [this, select_tool] {
|
||||
push_polygon_params();
|
||||
select_tool(DesignSketchTool::Mode::Polygon,
|
||||
wxString::Format(_L("Click center then a vertex — %d sides, %s"),
|
||||
m_poly_sides,
|
||||
m_poly_circumscribed ? _L("circumscribed") : _L("inscribed")));
|
||||
wxString::Format(m_poly_circumscribed
|
||||
? _L_PLURAL("Click center then a vertex — %d side, circumscribed",
|
||||
"Click center then a vertex — %d sides, circumscribed", m_poly_sides)
|
||||
: _L_PLURAL("Click center then a vertex — %d side, inscribed",
|
||||
"Click center then a vertex — %d sides, inscribed", m_poly_sides),
|
||||
m_poly_sides));
|
||||
};
|
||||
for (int n : {3, 4, 5, 6, 8, 12})
|
||||
m_verb_actions["btn:poly#" + std::to_string(n)] =
|
||||
@@ -1998,7 +2001,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
hform->Add(m_hole_target_label, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
m_box_hole = new wxBoxSizer(wxVERTICAL);
|
||||
m_box_hole->Add(card_header(m_cards, "design_hole", _L("Hole"), m_hdr_hole), 0, wxLEFT | wxRIGHT | wxTOP, 12);
|
||||
m_box_hole->Add(card_header(m_cards, "design_hole", _L_CONTEXT("Hole", "Design"), m_hdr_hole), 0, wxLEFT | wxRIGHT | wxTOP, 12);
|
||||
m_box_hole->Add(new wxStaticLine(m_cards), 0, wxEXPAND | wxALL, 8);
|
||||
m_box_hole->Add(hform, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 12);
|
||||
cards->Add(m_box_hole, 0, wxEXPAND);
|
||||
@@ -2022,7 +2025,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
m_thread_std->Append(s.name);
|
||||
m_thread_std->SetSelection(0);
|
||||
m_thread_std->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { apply_thread_standard(); });
|
||||
tform->Add(new wxStaticText(m_cards, wxID_ANY, _L("Standard")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
tform->Add(new wxStaticText(m_cards, wxID_ANY, _L_CONTEXT("Standard", "Thread standard")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
tform->Add(m_thread_std, 0, wxEXPAND);
|
||||
|
||||
// Threads are specified by DIAMETER (M6 = Ø6); the value is derived from the picked cylindrical
|
||||
@@ -2233,7 +2236,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
|
||||
m_cut_plane = make_combo(m_cards);
|
||||
m_cut_plane->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { refresh_preview(); });
|
||||
cform->Add(new wxStaticText(m_cards, wxID_ANY, _L("Plane")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
cform->Add(new wxStaticText(m_cards, wxID_ANY, _L_CONTEXT("Plane", "Design")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
cform->Add(m_cut_plane, 0, wxEXPAND);
|
||||
|
||||
m_cut_offset = make_spin(m_cards, 0.0, -10000.0, 10000.0);
|
||||
@@ -2258,7 +2261,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
|
||||
// --- Plane (datum/reference plane: offset + tilt from a base plane; no solid) ---
|
||||
m_box_plane = new wxBoxSizer(wxVERTICAL);
|
||||
m_box_plane->Add(card_header(m_cards, "design_plane", _L("Plane"), m_hdr_plane), 0, wxLEFT | wxRIGHT | wxTOP, 12);
|
||||
m_box_plane->Add(card_header(m_cards, "design_plane", _L_CONTEXT("Plane", "Design"), m_hdr_plane), 0, wxLEFT | wxRIGHT | wxTOP, 12);
|
||||
m_box_plane->Add(new wxStaticLine(m_cards), 0, wxEXPAND | wxALL, 8);
|
||||
{
|
||||
// Plane type chooses which inputs matter (Onshape/Fusion parity):
|
||||
@@ -2570,7 +2573,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
|
||||
// --- Mirror (reflect a body about a plane) ---
|
||||
m_box_mirror = new wxBoxSizer(wxVERTICAL);
|
||||
m_box_mirror->Add(card_header(m_cards, "design_mirror", _L("Mirror"), m_hdr_mirror), 0, wxLEFT | wxRIGHT | wxTOP, 12);
|
||||
m_box_mirror->Add(card_header(m_cards, "design_mirror", _L_CONTEXT("Mirror", "Design"), m_hdr_mirror), 0, wxLEFT | wxRIGHT | wxTOP, 12);
|
||||
m_box_mirror->Add(new wxStaticLine(m_cards), 0, wxEXPAND | wxALL, 8);
|
||||
{
|
||||
auto* mform = two_col_form();
|
||||
@@ -2748,7 +2751,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
m_helix_plane = make_combo(m_cards);
|
||||
populate_plane_choices(m_helix_plane);
|
||||
m_helix_plane->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { refresh_preview(); });
|
||||
hform->Add(new wxStaticText(m_cards, wxID_ANY, _L("Plane")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
hform->Add(new wxStaticText(m_cards, wxID_ANY, _L_CONTEXT("Plane", "Design")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
hform->Add(m_helix_plane, 0, wxEXPAND);
|
||||
m_helix_radius = make_spin(m_cards, 10.0, 0.01, 10000.0);
|
||||
m_helix_radius->Bind(wxEVT_SPINCTRLDOUBLE, [this](wxSpinDoubleEvent&) { refresh_preview(); });
|
||||
@@ -3556,7 +3559,9 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
m_doc.recompute();
|
||||
set_status(StatusKind::Info, cons.empty()
|
||||
? _L("Sketch created — select it, then right-click to Extrude")
|
||||
: wxString::Format(_L("Sketch created (%zu driving dims) — select it, then right-click to Extrude"),
|
||||
: wxString::Format(_L_PLURAL("Sketch created (%zu driving dim) — select it, then right-click to Extrude",
|
||||
"Sketch created (%zu driving dims) — select it, then right-click to Extrude",
|
||||
unsigned(cons.size())),
|
||||
cons.size()));
|
||||
refresh_tree();
|
||||
sync_sketch_display(); // keep the just-committed sketch visible as a face
|
||||
@@ -4585,8 +4590,8 @@ void DesignPanel::on_shape_changed()
|
||||
|
||||
void DesignPanel::set_status_ok()
|
||||
{
|
||||
set_status(wxString::Format(_L("OK — %zu triangles"),
|
||||
m_doc.display_mesh.its.indices.size()));
|
||||
const size_t n_tris = m_doc.display_mesh.its.indices.size();
|
||||
set_status(wxString::Format(_L_PLURAL("OK — %zu triangle", "OK — %zu triangles", unsigned(n_tris)), n_tris));
|
||||
if (m_viewport != nullptr) {
|
||||
// A recompute invalidates the gizmo's body centroid; a Move ends with it, keeping its pose.
|
||||
if (body_move_pending()) end_body_move(true);
|
||||
@@ -5035,11 +5040,15 @@ void DesignPanel::on_import_mesh()
|
||||
// A dense organic scan has few coplanar neighbours to merge away and stays heavy afterwards;
|
||||
// warn rather than silently freezing the CAD kernel on every subsequent recompute.
|
||||
if (mesh.its.indices.size() > MESH_IMPORT_TRIANGLE_WARN) {
|
||||
const int n_tris = int(mesh.its.indices.size());
|
||||
const wxString q = wxString::Format(
|
||||
_L("This mesh has %d triangles. Every triangle becomes a B-rep face before coplanar "
|
||||
"merging, so importing it may take a long time and leave a body that is slow to "
|
||||
"edit. Decimating the mesh first is usually better.\n\nImport anyway?"),
|
||||
int(mesh.its.indices.size()));
|
||||
_L_PLURAL("This mesh has %d triangle. Every triangle becomes a B-rep face before coplanar "
|
||||
"merging, so importing it may take a long time and leave a body that is slow to "
|
||||
"edit. Decimating the mesh first is usually better.\n\nImport anyway?",
|
||||
"This mesh has %d triangles. Every triangle becomes a B-rep face before coplanar "
|
||||
"merging, so importing it may take a long time and leave a body that is slow to "
|
||||
"edit. Decimating the mesh first is usually better.\n\nImport anyway?", n_tris),
|
||||
n_tris);
|
||||
MessageDialog dlg(this, q, _L("Large mesh"), wxYES_NO | wxICON_WARNING);
|
||||
if (dlg.ShowModal() != wxID_YES)
|
||||
return;
|
||||
@@ -5080,7 +5089,7 @@ void DesignPanel::on_import_mesh()
|
||||
// source mesh the user needs to know about before they start cutting features into it.
|
||||
if (stats.is_solid) {
|
||||
set_status(StatusKind::Info, wxString::Format(
|
||||
_L("Imported solid — %d triangles → %d faces, volume %.2f mm³. Pick a face or edge, "
|
||||
_L("Imported solid — triangles: %d → faces: %d, volume %.2f mm³. Pick a face or edge, "
|
||||
"then Fillet / Cut / Shell to modify"),
|
||||
stats.kept_tris, stats.faces_final, stats.volume));
|
||||
} else {
|
||||
@@ -5171,7 +5180,8 @@ void DesignPanel::open_insert_card(const wxString& base_name)
|
||||
update_cards_frame(); m_form->Layout();
|
||||
m_form->FitInside();
|
||||
update_action_bar(); // surface the unified ✓/✗
|
||||
set_status(StatusKind::Info, base_name + _L(" — drag to place/size, then Confirm"));
|
||||
// TRN Design tab status; %s is the inserted item, such as "Text" or "SVG".
|
||||
set_status(StatusKind::Info, wxString::Format(_L("%s — drag to place/size, then Confirm"), base_name));
|
||||
}
|
||||
|
||||
// Confirm: keep the placed art and leave the placement gizmo. The feature is already in
|
||||
@@ -5255,7 +5265,7 @@ void DesignPanel::on_add_extrude()
|
||||
{
|
||||
BooleanMode mode = static_cast<BooleanMode>(m_mode->GetSelection()); // New/Add/Cut/Intersect
|
||||
m_feature_counter++;
|
||||
const std::string name = feature_name(_L("Extrude"));
|
||||
const std::string name = feature_name(_L_CONTEXT("Extrude", "Design"));
|
||||
int idx = -1;
|
||||
if (m_extrude_face_src >= 0) {
|
||||
// Onshape face-extrude: the picked solid face is the profile (no sketch wire).
|
||||
@@ -5383,7 +5393,7 @@ void DesignPanel::on_add_hole()
|
||||
|
||||
m_feature_counter++;
|
||||
const int hidx = m_doc.add_hole(dia, depth, through, px, py, plane,
|
||||
feature_name(_L("Hole")));
|
||||
feature_name(_L_CONTEXT("Hole", "Design")));
|
||||
// On-face holes drill the body the face belongs to (even after the pick was cleared).
|
||||
if (m_hole_on_face && hidx >= 0 && hidx < int(m_doc.features.size()))
|
||||
m_doc.features[hidx].target_body = m_hole_face_body;
|
||||
@@ -5770,7 +5780,7 @@ void DesignPanel::on_add_mirror()
|
||||
const BooleanMode mode = m_mirror_keep->GetValue() ? BooleanMode::New : BooleanMode::Add;
|
||||
m_feature_counter++;
|
||||
m_doc.add_mirror(plane_from_choice(m_mirror_plane->GetSelection()), target, mode,
|
||||
feature_name(_L("Mirror")));
|
||||
feature_name(_L_CONTEXT("Mirror", "Design")));
|
||||
if (!recompute_guarded(_L("Rebuilding model…")))
|
||||
set_status(StatusKind::Error, wxString::Format(_L("The model could not be rebuilt: %s"), kernel_error_text(m_doc.error)));
|
||||
else
|
||||
@@ -5817,7 +5827,7 @@ void DesignPanel::on_add_rib()
|
||||
}
|
||||
m_feature_counter++;
|
||||
m_doc.add_rib(sketch_ref, m_rib_entity->GetValue(), m_rib_thickness->GetValue(),
|
||||
m_rib_depth->GetValue(), target, feature_name(_L("Rib")));
|
||||
m_rib_depth->GetValue(), target, feature_name(_L_CONTEXT("Rib", "Design")));
|
||||
if (!recompute_guarded(_L("Rebuilding model…")))
|
||||
set_status(StatusKind::Error, wxString::Format(_L("The model could not be rebuilt: %s"), kernel_error_text(m_doc.error)));
|
||||
else
|
||||
@@ -5837,7 +5847,7 @@ void DesignPanel::on_add_project()
|
||||
m_feature_counter++;
|
||||
m_doc.add_project_edges(src_body, {}, face,
|
||||
plane_from_choice(m_proj_plane->GetSelection()),
|
||||
feature_name(_L("Project")));
|
||||
feature_name(_L_CONTEXT("Project", "Design")));
|
||||
if (!recompute_guarded(_L("Rebuilding model…")))
|
||||
set_status(StatusKind::Error, wxString::Format(_L("The model could not be rebuilt: %s"), kernel_error_text(m_doc.error)));
|
||||
else
|
||||
@@ -6024,7 +6034,7 @@ void DesignPanel::on_add_pattern()
|
||||
m_doc.add_pattern(circular, int(m_pattern_count->GetValue()),
|
||||
m_pattern_spacing->GetValue(), m_pattern_dir->GetSelection(),
|
||||
m_pattern_angle->GetValue(), target,
|
||||
feature_name(_L("Pattern")));
|
||||
feature_name(_L_CONTEXT("Pattern", "Design")));
|
||||
|
||||
if (!recompute_guarded(_L("Rebuilding model…")))
|
||||
set_status(StatusKind::Error, wxString::Format(_L("The model could not be rebuilt: %s"), kernel_error_text(m_doc.error)));
|
||||
@@ -6126,7 +6136,7 @@ void DesignPanel::on_add_cut()
|
||||
m_feature_counter++;
|
||||
m_doc.add_cut(plane_from_choice(m_cut_plane->GetSelection()), m_cut_offset->GetValue(),
|
||||
/*flip*/ false, /*keep_upper*/ true, /*keep_lower*/ true,
|
||||
m_cut_target->GetSelection(), feature_name(_L("Cut")));
|
||||
m_cut_target->GetSelection(), feature_name(_L_CONTEXT("Cut", "Design")));
|
||||
if (!recompute_guarded(_L("Rebuilding model…")))
|
||||
set_status(StatusKind::Error, wxString::Format(_L("The model could not be rebuilt: %s"), kernel_error_text(m_doc.error)));
|
||||
else
|
||||
@@ -6429,7 +6439,8 @@ static wxString sketch_step_prompt(DesignSketchTool::Mode m, int step, int picks
|
||||
using Mode = DesignSketchTool::Mode;
|
||||
auto pick_more = [](const wxString& lead, int n) {
|
||||
return n <= 0 ? lead
|
||||
: lead + wxString::Format(_L(" · %d picked"), n);
|
||||
// TRN Appended to a sketch tool prompt; %d is the number of picked entities.
|
||||
: lead + wxString::Format(_L_PLURAL(" · %d picked", " · %d picked", n), n);
|
||||
};
|
||||
switch (m) {
|
||||
case Mode::Select:
|
||||
@@ -6442,8 +6453,10 @@ static wxString sketch_step_prompt(DesignSketchTool::Mode m, int step, int picks
|
||||
"Shift-click adds · Del removes");
|
||||
case Mode::Constrain:
|
||||
return picks > 0
|
||||
? wxString::Format(_L("%d picked · now choose a constraint (Horizontal, Parallel, "
|
||||
"Tangent, Equal…)"), picks)
|
||||
? wxString::Format(_L_PLURAL("%d picked · now choose a constraint (Horizontal, Parallel, "
|
||||
"Tangent, Equal…)",
|
||||
"%d picked · now choose a constraint (Horizontal, Parallel, "
|
||||
"Tangent, Equal…)", picks), picks)
|
||||
: _L("Constrain — click one or two entities, then choose a constraint");
|
||||
case Mode::Dimension:
|
||||
return step == 0 ? _L("Dimension — click an entity, or the first of two points")
|
||||
@@ -6544,8 +6557,10 @@ static wxString sketch_step_prompt(DesignSketchTool::Mode m, int step, int picks
|
||||
? _L("Mirror — first click the LINE to mirror about (a construction line works)")
|
||||
: picks == 0
|
||||
? _L("Mirror — axis set · now click the entities to mirror · Esc cancels")
|
||||
: wxString::Format(_L("Mirror — axis set · %d to mirror · click another to add or "
|
||||
"remove it · Enter applies"), picks);
|
||||
: wxString::Format(_L_PLURAL("Mirror — axis set · %d to mirror · click another to add or "
|
||||
"remove it · Enter applies",
|
||||
"Mirror — axis set · %d to mirror · click another to add or "
|
||||
"remove it · Enter applies", picks), picks);
|
||||
case Mode::Move:
|
||||
return step == 0 ? _L("Move — click the entities to move")
|
||||
: pick_more(_L("Move — drag the handle, or click the number to type the "
|
||||
@@ -6653,7 +6668,7 @@ wxString DesignPanel::offer_header(int kind) const
|
||||
case OfferSel::SkPoint: return _L("Sketch point");
|
||||
case OfferSel::Sk2Ent: {
|
||||
const int n = m_viewport ? m_viewport->sketch_selection_count() : 0;
|
||||
return wxString::Format(_L("%d sketch entities"), n);
|
||||
return wxString::Format(_L_PLURAL("%d sketch entity", "%d sketch entities", n), n);
|
||||
}
|
||||
default: return wxString();
|
||||
}
|
||||
@@ -6753,7 +6768,7 @@ void DesignPanel::show_offer_menu(const wxPoint& screen_pos)
|
||||
} else {
|
||||
offer_trace("row=%d %s DISABLED (%s)", row, kOfferRowNames[row],
|
||||
v->refusal ? v->refusal : "blocked");
|
||||
wxString s = tr(v->name);
|
||||
wxString s = I18N::translate(v->name, "Design");
|
||||
if (v->refusal) s += wxString::FromUTF8(" — ") + tr(v->refusal);
|
||||
append_offer_item(&menu, id, s, *v)->Enable(false);
|
||||
bound.push_back(nullptr);
|
||||
@@ -6828,7 +6843,7 @@ void DesignPanel::show_offer_menu(const wxPoint& screen_pos)
|
||||
}
|
||||
if (!ok) {
|
||||
offer_trace("row=%d %s ~ %s BLOCKED", row, kOfferRowNames[row], v->id);
|
||||
wxString s = tr(v->name);
|
||||
wxString s = I18N::translate(v->name, "Design");
|
||||
if (v->refusal) s += wxString::FromUTF8(" — ") + tr(v->refusal);
|
||||
append_offer_item(target, base + int(bound.size()), s, *v)->Enable(false);
|
||||
bound.push_back(nullptr);
|
||||
@@ -6935,8 +6950,8 @@ void DesignPanel::show_offer_menu(const wxPoint& screen_pos)
|
||||
if (i < 0 || i >= int(opts.size()) || !opts[i].viable) return;
|
||||
drop_ghost(); // the real bodies are about to become the ghost's pose
|
||||
m_doc.checkpoint(); // undo boundary: committing a mate from the offer
|
||||
int idx = m_doc.add_mate(opts[i].kind, cs_a, cs_b, 0.0, 0.0, false,
|
||||
"Mate" + std::to_string(++m_feature_counter));
|
||||
++m_feature_counter;
|
||||
int idx = m_doc.add_mate(opts[i].kind, cs_a, cs_b, 0.0, 0.0, false, feature_name(_L("Mate")));
|
||||
if (idx < 0) {
|
||||
set_status(StatusKind::Error, _L("Mate rejected"));
|
||||
return;
|
||||
@@ -7165,7 +7180,7 @@ bool DesignPanel::on_add_plane()
|
||||
m_feature_counter++;
|
||||
int idx = m_doc.add_plane(m_plane_base->GetSelection(), m_plane_offset->GetValue(),
|
||||
m_plane_tilt->GetValue(), m_plane_tilt_axis->GetSelection(),
|
||||
feature_name(_L("Plane")));
|
||||
feature_name(_L_CONTEXT("Plane", "Design")));
|
||||
if (idx >= 0 && idx < int(m_doc.features.size())) apply_plane_refs(m_doc.features[idx]);
|
||||
m_doc.recompute(); // datum-only docs yield no body; that is expected/benign
|
||||
set_status(StatusKind::Info, _L("Plane added — pick it as a sketch plane"));
|
||||
@@ -7206,7 +7221,7 @@ void DesignPanel::on_add_shell()
|
||||
|
||||
m_feature_counter++;
|
||||
m_doc.add_shell(m_shell_thickness->GetValue(), face, m_sel_solid_body,
|
||||
feature_name(_L("Shell")));
|
||||
feature_name(_L_CONTEXT("Shell", "Design")));
|
||||
|
||||
if (!recompute_guarded(_L("Rebuilding model…")))
|
||||
set_status(StatusKind::Error, wxString::Format(_L("The model could not be rebuilt: %s"), kernel_error_text(m_doc.error)));
|
||||
@@ -9500,7 +9515,8 @@ void DesignPanel::request_value(const wxString& label, double def, double mn, do
|
||||
m_form->FitInside();
|
||||
m_value_input->SetFocus();
|
||||
m_value_input->SetSelection(-1, -1); // select all so typing replaces the value
|
||||
set_status(StatusKind::Info, label + _L(" — type a value, press Enter (or Confirm)"));
|
||||
// TRN Design tab status; %s is the value being asked for, such as "Fillet radius".
|
||||
set_status(StatusKind::Info, wxString::Format(_L("%s — type a value, press Enter (or Confirm)"), label));
|
||||
}
|
||||
|
||||
void DesignPanel::confirm_value()
|
||||
@@ -10228,19 +10244,19 @@ void DesignPanel::on_commit()
|
||||
for (size_t b = 0; b < m_disp_body_meshes.size(); ++b) {
|
||||
if (b < m_body_visible.size() && !m_body_visible[b]) continue; // skip hidden
|
||||
if (m_disp_body_meshes[b].its.indices.empty()) continue;
|
||||
parts.emplace_back(&m_disp_body_meshes[b], wxString::FromUTF8("Design Body " + std::to_string(b + 1)));
|
||||
parts.emplace_back(&m_disp_body_meshes[b], wxString::Format(_L("Design Body %d"), int(b + 1)));
|
||||
}
|
||||
if (parts.empty()) { // every body hidden — nothing to ship
|
||||
set_status(_L("All bodies hidden — show one before committing"));
|
||||
return;
|
||||
}
|
||||
if (m_commit_mode == CommitMode::Assembly && parts.size() > 1)
|
||||
obj_list->load_mesh_object(parts, "Design Assembly");
|
||||
obj_list->load_mesh_object(parts, _L("Design Assembly"));
|
||||
else
|
||||
for (const auto& [mesh, name] : parts)
|
||||
obj_list->load_mesh_object(*mesh, name);
|
||||
} else {
|
||||
obj_list->load_mesh_object(m_disp_pick_mesh, "Design Body");
|
||||
obj_list->load_mesh_object(m_disp_pick_mesh, _L("Design Body"));
|
||||
}
|
||||
|
||||
// Persist the editable parametric recipe alongside the committed meshes so the
|
||||
@@ -11478,7 +11494,8 @@ void DesignPanel::refresh_preview()
|
||||
|
||||
if (ok) {
|
||||
m_viewport->set_preview_mesh(mesh);
|
||||
set_status(StatusKind::Ok, wxString::Format(_L("Preview — %zu triangles"), mesh.its.indices.size()));
|
||||
const size_t n_tris = mesh.its.indices.size();
|
||||
set_status(StatusKind::Ok, wxString::Format(_L_PLURAL("Preview — %zu triangle", "Preview — %zu triangles", unsigned(n_tris)), n_tris));
|
||||
} else {
|
||||
m_viewport->clear_preview();
|
||||
set_status(StatusKind::Error, wxString::Format(_L("Invalid: %s"), kernel_error_text(err)));
|
||||
@@ -11789,13 +11806,13 @@ void DesignPanel::open_tool(Tool t)
|
||||
case Tool::Extrude: m_hdr_extrude->SetLabel(title(_L_CONTEXT("Extrude", "Design"))); break;
|
||||
case Tool::Dressup: m_hdr_dressup->SetLabel(title(
|
||||
m_dressup_type->GetSelection() == 0 ? _L("Fillet") : _L("Chamfer"))); break;
|
||||
case Tool::Hole: m_hdr_hole->SetLabel(title(_L("Hole"))); break;
|
||||
case Tool::Hole: m_hdr_hole->SetLabel(title(_L_CONTEXT("Hole", "Design"))); break;
|
||||
case Tool::Thread: m_hdr_thread->SetLabel(title(_L("Thread"))); break;
|
||||
case Tool::Shell: m_hdr_shell->SetLabel(title(_L_CONTEXT("Shell", "Design"))); break;
|
||||
case Tool::Revolve: m_hdr_revolve->SetLabel(title(_L("Revolve"))); break;
|
||||
case Tool::Sweep: m_hdr_sweep->SetLabel(title(_L("Sweep"))); break;
|
||||
case Tool::Pattern: m_hdr_pattern->SetLabel(title(_L_CONTEXT("Pattern", "Design"))); break;
|
||||
case Tool::Plane: m_hdr_plane->SetLabel(title(_L("Plane"))); break;
|
||||
case Tool::Plane: m_hdr_plane->SetLabel(title(_L_CONTEXT("Plane", "Design"))); break;
|
||||
case Tool::Loft: m_hdr_loft->SetLabel(title(_L("Loft"))); break;
|
||||
case Tool::Draft: m_hdr_draft->SetLabel(title(_L("Draft"))); break;
|
||||
case Tool::Boolean: m_hdr_boolean->SetLabel(title(_L("Boolean"))); break;
|
||||
@@ -11809,7 +11826,7 @@ void DesignPanel::open_tool(Tool t)
|
||||
case Tool::SurfaceOffset: m_hdr_surf_offset->SetLabel(title(_L("Surface Offset"))); break;
|
||||
case Tool::ThickenSurface: m_hdr_surf_thicken->SetLabel(title(_L("Thicken Surface"))); break;
|
||||
case Tool::Transform: m_hdr_transform->SetLabel(title(_L("Transform"))); break;
|
||||
case Tool::Mirror: m_hdr_mirror->SetLabel(title(_L("Mirror"))); break;
|
||||
case Tool::Mirror: m_hdr_mirror->SetLabel(title(_L_CONTEXT("Mirror", "Design"))); break;
|
||||
case Tool::Thicken: m_hdr_thicken->SetLabel(title(_L("Thicken"))); break;
|
||||
case Tool::Rib: m_hdr_rib->SetLabel(title(_L_CONTEXT("Rib", "Design"))); break;
|
||||
case Tool::Project: m_hdr_project->SetLabel(title(_L_CONTEXT("Project", "Design"))); break;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "slic3r/GUI/CAD/SketchInlineEditor.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "libslic3r/format.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
@@ -902,8 +903,11 @@ void DesignSketchTool::resolve_live_drag(int dragged_ei, SketchPointRole dragged
|
||||
if (int(r.skipped.size()) != m_skipped_last) {
|
||||
m_skipped_last = int(r.skipped.size());
|
||||
if (m_skipped_last > 0)
|
||||
notify(format(_u8L("%1% constraint(s) cannot act on this geometry (an ellipse or spline curve, "
|
||||
"or a zero-size circle) and are ignored"), m_skipped_last), false);
|
||||
notify(format(into_u8(_L_PLURAL("%1% constraint cannot act on this geometry (an ellipse or spline curve, "
|
||||
"or a zero-size circle) and is ignored",
|
||||
"%1% constraints cannot act on this geometry (an ellipse or spline curve, "
|
||||
"or a zero-size circle) and are ignored", m_skipped_last)),
|
||||
m_skipped_last), false);
|
||||
}
|
||||
// Flag every entity referenced by a conflicting constraint so render() can
|
||||
// tint it red (Onshape/SolveSpace over-constrained feedback), and remember which
|
||||
@@ -8978,7 +8982,8 @@ void DesignSketchTool::confirm_op()
|
||||
|| self_len(d, a) || self_len(d, b);
|
||||
});
|
||||
if (released > 0)
|
||||
notify(format(_u8L("%1% constraint(s) the fillet/chamfer invalidated were removed"), released), false);
|
||||
notify(format(into_u8(_L_PLURAL("%1% constraint the fillet/chamfer invalidated was removed",
|
||||
"%1% constraints the fillet/chamfer invalidated were removed", released)), released), false);
|
||||
auto coin = [&](R xr, int ln, R lr) {
|
||||
SketchEntityConstraintDef d; d.type = CT::Coincident; d.ea = xi; d.ra = xr; d.eb = ln; d.rb = lr; return d; };
|
||||
if (fillet) {
|
||||
@@ -9427,7 +9432,8 @@ void DesignSketchTool::confirm_transform()
|
||||
}
|
||||
});
|
||||
if (released > 0)
|
||||
notify(format(_u8L("%1% constraint(s) released by the transform"), released), false);
|
||||
notify(format(into_u8(_L_PLURAL("%1% constraint released by the transform",
|
||||
"%1% constraints released by the transform", released)), released), false);
|
||||
} else if (m_mode == Mode::Array || m_mode == Mode::PolarArray) {
|
||||
// ADDITIVE: append copies of each subject, then bind each copy to its source. Lines
|
||||
// get Parallel+EqualLength (linear) or EqualLength only (polar — rotation breaks
|
||||
|
||||
@@ -559,7 +559,7 @@ int HistoryWindow::get_extruder_id()
|
||||
void HistoryWindow::on_click_new_button(wxCommandEvent& event)
|
||||
{
|
||||
if (curr_obj && curr_obj->get_printer_series() == PrinterSeries::SERIES_P1P && m_calib_results_history.size() >= 16) {
|
||||
MessageDialog msg_dlg(nullptr, wxString::Format(_L("This machine type can only hold %d historical results per nozzle."), 16), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
MessageDialog msg_dlg(nullptr, wxString::Format(_L_PLURAL("This machine type can only hold %d historical result per nozzle.", "This machine type can only hold %d historical results per nozzle.", 16), 16), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -973,7 +973,7 @@ bool PressureAdvanceWizard::can_save_cali_result(const std::vector<PACalibResult
|
||||
}
|
||||
|
||||
if (curr_obj->get_printer_series() != PrinterSeries::SERIES_X1 && curr_obj->pa_calib_tab.size() >= MAX_PA_HISTORY_RESULTS_NUMS) {
|
||||
MessageDialog msg_dlg(nullptr, wxString::Format(_L("This machine type can only hold %d historical results per nozzle. This result will not be saved."), MAX_PA_HISTORY_RESULTS_NUMS),
|
||||
MessageDialog msg_dlg(nullptr, wxString::Format(_L_PLURAL("This machine type can only hold %d historical result per nozzle. This result will not be saved.", "This machine type can only hold %d historical results per nozzle. This result will not be saved.", MAX_PA_HISTORY_RESULTS_NUMS), MAX_PA_HISTORY_RESULTS_NUMS),
|
||||
wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return false;
|
||||
|
||||
@@ -352,7 +352,9 @@ void CalibrationCaliPage::update_subtask(MachineObject* obj)
|
||||
prepare_text = wxString::Format(_L("Cloud Slicing..."));
|
||||
}
|
||||
else {
|
||||
prepare_text = wxString::Format(_L("In Cloud Slicing Queue, there are %s tasks ahead of you."), std::to_string(obj->queue_number));
|
||||
prepare_text = wxString::Format(_L_PLURAL("In Cloud Slicing Queue, there is %d task ahead of you.",
|
||||
"In Cloud Slicing Queue, there are %d tasks ahead of you.", obj->queue_number),
|
||||
obj->queue_number);
|
||||
show_percent = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ CaliPageButton::CaliPageButton(wxWindow* parent, CaliPageActionType type, wxStri
|
||||
this->SetLabel(_L("Finish"));
|
||||
break;
|
||||
default:
|
||||
this->SetLabel("Unknown");
|
||||
this->SetLabel(_L("Unknown"));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -644,9 +644,9 @@ void CalibrationPresetPage::create_selection_panel(wxWindow* parent)
|
||||
|
||||
for (const auto& extruder : curr_obj->GetExtderSystem()->GetExtruders()) {
|
||||
if (extruder.GetNozzleType() == NozzleType::ntUndefine) {
|
||||
wxString name = _L("left");
|
||||
if (extruder.GetExtId() == 0) { name = _L("right"); }
|
||||
wxString msg = wxString::Format(_L("Printer %s nozzle information has not been set. Please configure it before proceeding with the calibration."), name);
|
||||
wxString msg = extruder.GetExtId() == 0 ?
|
||||
_L("Printer right nozzle information has not been set. Please configure it before proceeding with the calibration.") :
|
||||
_L("Printer left nozzle information has not been set. Please configure it before proceeding with the calibration.");
|
||||
MessageDialog msg_dlg(nullptr, msg, wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
break;
|
||||
@@ -2815,7 +2815,7 @@ MaxVolumetricSpeedPresetPage::MaxVolumetricSpeedPresetPage(
|
||||
wxArrayString titles;
|
||||
titles.push_back(_L("From Volumetric Speed"));
|
||||
titles.push_back(_L("To Volumetric Speed"));
|
||||
titles.push_back(_L("Step"));
|
||||
titles.push_back(_L_CONTEXT("Step", "Increment"));
|
||||
m_custom_range_panel->set_titles(titles);
|
||||
|
||||
m_custom_range_panel->set_unit(_L("mm³/s"));
|
||||
|
||||
@@ -680,16 +680,15 @@ void ColorDecomposeDialog::update_filament_limit_warning()
|
||||
return;
|
||||
}
|
||||
|
||||
wxString mode_name;
|
||||
switch (m_selected_mode) {
|
||||
case DecomposeMode::CMYW: mode_name = "CMYW"; break;
|
||||
case DecomposeMode::RYBW: mode_name = "RYBW"; break;
|
||||
case DecomposeMode::MaterialList: mode_name = _L("Material List"); break;
|
||||
}
|
||||
|
||||
const wxString warning_text = format_wxstr(
|
||||
_L("The material list supports at most %1% colors. After %2% decomposition, the material count would exceed %1%. Please delete unused filaments on the main screen before decomposing."),
|
||||
m_max_filament_count, mode_name);
|
||||
const unsigned int max_count = static_cast<unsigned int>(m_max_filament_count);
|
||||
const wxString warning_text = m_selected_mode == DecomposeMode::MaterialList ?
|
||||
format_wxstr(_L_PLURAL("The material list supports at most %1% color. After Material List decomposition, the material count would exceed %1%. Please delete unused filaments on the main screen before decomposing.",
|
||||
"The material list supports at most %1% colors. After Material List decomposition, the material count would exceed %1%. Please delete unused filaments on the main screen before decomposing.",
|
||||
max_count), max_count) :
|
||||
// TRN %2% is the decomposition mode name, "CMYW" or "RYBW"
|
||||
format_wxstr(_L_PLURAL("The material list supports at most %1% color. After %2% decomposition, the material count would exceed %1%. Please delete unused filaments on the main screen before decomposing.",
|
||||
"The material list supports at most %1% colors. After %2% decomposition, the material count would exceed %1%. Please delete unused filaments on the main screen before decomposing.",
|
||||
max_count), max_count, m_selected_mode == DecomposeMode::CMYW ? "CMYW" : "RYBW");
|
||||
|
||||
// Show first so the panel is laid out and the text control gets its real
|
||||
// width, then wrap to that width so the paragraph fills the content area.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "format.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
@@ -340,8 +341,9 @@ bool prepare_decompose_mixed_result(
|
||||
missing_comp.component_idx = out_result.components.size();
|
||||
missing_comp.official_component = official_component;
|
||||
missing_comp.preset_name = preset_name;
|
||||
missing_comp.display_name = decompose_base_color_display(comp.base_color) +
|
||||
wxString::FromUTF8(" ") + wxString::FromUTF8(basic_type);
|
||||
// TRN %1% is a color name such as "Cyan", %2% is a filament type such as "PLA Basic"
|
||||
missing_comp.display_name = format_wxstr(_L_CONTEXT("%1% %2%", "Color and filament type"),
|
||||
decompose_base_color_display(comp.base_color), wxString::FromUTF8(basic_type));
|
||||
missing.push_back(std::move(missing_comp));
|
||||
out_result.components.push_back(0);
|
||||
}
|
||||
@@ -407,8 +409,11 @@ bool confirm_create_decompose_missing_components(wxWindow* parent, const std::ve
|
||||
missing_text += missing[i].display_name;
|
||||
}
|
||||
|
||||
wxString message = wxString::Format(_L("The current filament list does not contain %s. A project filament required by "
|
||||
"the mixed filament will be created automatically after decomposition."),
|
||||
wxString message = wxString::Format(_L_PLURAL("The current filament list does not contain %s. A project filament required by "
|
||||
"the mixed filament will be created automatically after decomposition.",
|
||||
"The current filament list does not contain %s. Project filaments required by "
|
||||
"the mixed filament will be created automatically after decomposition.",
|
||||
missing.size()),
|
||||
missing_text);
|
||||
|
||||
MessageDialog dlg(parent, message, _L("Tip"), wxOK | wxCANCEL | wxICON_INFORMATION);
|
||||
|
||||
@@ -35,7 +35,7 @@ CrealityDiscoveryDialog::CrealityDiscoveryDialog(wxWindow* parent)
|
||||
m_list = new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||
wxLC_REPORT | wxSIMPLE_BORDER | wxLC_SINGLE_SEL);
|
||||
m_list->SetMinSize(wxSize(50 * em, 18 * em));
|
||||
m_list->AppendColumn(_L("Model"), wxLIST_FORMAT_LEFT, 8 * em);
|
||||
m_list->AppendColumn(_L_CONTEXT("Model", "Printer model"), wxLIST_FORMAT_LEFT, 8 * em);
|
||||
m_list->AppendColumn(_L("Hostname"), wxLIST_FORMAT_LEFT, 14 * em);
|
||||
m_list->AppendColumn(_L("IP"), wxLIST_FORMAT_LEFT, 14 * em);
|
||||
|
||||
@@ -109,7 +109,8 @@ void CrealityDiscoveryDialog::run_discovery()
|
||||
"network and not blocked by Wi-Fi client isolation, then click Scan again."));
|
||||
} else {
|
||||
m_status->SetLabel(wxString::Format(
|
||||
_L("Found %zu Creality printer(s). Select one and click Use Selected."),
|
||||
_L_PLURAL("Found %zu Creality printer. Select it and click Use Selected.",
|
||||
"Found %zu Creality printers. Select one and click Use Selected.", m_rows.size()),
|
||||
m_rows.size()));
|
||||
m_list->Select(0);
|
||||
}
|
||||
|
||||
@@ -4690,7 +4690,7 @@ void EditFilamentPresetDialog::delete_preset()
|
||||
if (count > 0) {
|
||||
msg = _L("Presets inherited by other presets cannot be deleted");
|
||||
msg += "\n";
|
||||
msg += _L_PLURAL("The following presets inherits this preset.", "The following preset inherits this preset.", count);
|
||||
msg += _L_PLURAL("The following preset inherits this preset.", "The following presets inherit this preset.", count);
|
||||
wxString title = _L("Delete Preset");
|
||||
MessageDialog(this, msg + presets, title, wxOK | wxICON_ERROR).ShowModal();
|
||||
m_selected_printer.clear();
|
||||
|
||||
@@ -389,8 +389,8 @@ static void s_update_title(const std::shared_ptr<DevNozzleRack> rack, wgtDeviceN
|
||||
wxString title = _L("Induction Hotend Rack");
|
||||
if (rack && (rack->GetReadingCount() > 0))
|
||||
{
|
||||
wxString pending = ": " + _L("Reading") + wxString::Format(" %d/%d", rack->GetReadingIdx(), rack->GetReadingCount());
|
||||
title += pending;
|
||||
// TRN %d/%d is the hotend being read and the number of hotends to read.
|
||||
title = wxString::Format(_L("Induction Hotend Rack: Reading %d/%d"), rack->GetReadingIdx(), rack->GetReadingCount());
|
||||
}
|
||||
|
||||
title_label->SetLabel(title);
|
||||
|
||||
@@ -385,7 +385,8 @@ void EditGCodeDialog::selection_changed(wxDataViewEvent& evt)
|
||||
// Orca: move below checking for def in custom defined G-code placeholders
|
||||
// This allows custom placeholders to override the default ones for this dialog
|
||||
// Override custom def if selection is within the preset category
|
||||
if (!def || m_params_list->GetSelectedTopLevelCategory() == "Presets") {
|
||||
// The group label is translated, so compare against the translated label.
|
||||
if (!def || m_params_list->GetSelectedTopLevelCategory() == _L("Presets").ToStdString()) {
|
||||
const auto& full_config = wxGetApp().preset_bundle->full_config();
|
||||
if (const ConfigDef* config_def = full_config.def(); config_def && config_def->has(opt_key)) {
|
||||
def = config_def->get(opt_key);
|
||||
|
||||
@@ -124,9 +124,13 @@ void FilamentMapManualPanel::OnTimer(wxTimerEvent &)
|
||||
m_errors->Hide();
|
||||
m_suggestion_panel->Hide();
|
||||
} else {
|
||||
m_errors->SetLabel(wxString::Format(_L("Error: %s extruder has no available %s nozzle, current group result is invalid."),
|
||||
invalid_eid == 0 ? _L_CONTEXT("Left", "Nozzle position") : _L_CONTEXT("Right", "Nozzle position"),
|
||||
invalid_nozzle == NozzleVolumeType::nvtStandard ? _L("Standard") : _L("High Flow")));
|
||||
// [extruder][nozzle volume type]
|
||||
static const char* const error_msgs[2][2] = {
|
||||
{L("Error: Left extruder has no available Standard nozzle, current group result is invalid."),
|
||||
L("Error: Left extruder has no available High Flow nozzle, current group result is invalid.")},
|
||||
{L("Error: Right extruder has no available Standard nozzle, current group result is invalid."),
|
||||
L("Error: Right extruder has no available High Flow nozzle, current group result is invalid.")}};
|
||||
m_errors->SetLabel(_(error_msgs[invalid_eid == 0 ? 0 : 1][invalid_nozzle == NozzleVolumeType::nvtStandard ? 0 : 1]));
|
||||
// Re-wrap: wrapping only applies to the label text present when Wrap is called,
|
||||
// and the label was empty at construction time.
|
||||
m_errors->Wrap(FromDIP(520));
|
||||
|
||||
@@ -3976,17 +3976,17 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
|
||||
imgui.text(_u8L("Current grouping of slice result is not optimal."));
|
||||
wxString tip;
|
||||
if (delta_weight_to_best >= 0 && delta_change_to_best >= 0)
|
||||
tip = from_u8((boost::format(_u8L("Increase %1%g filament and %2% changes compared to optimal grouping."))
|
||||
% number_format(delta_weight_to_best)
|
||||
% delta_change_to_best).str());
|
||||
tip = format_wxstr(_L_PLURAL("Increase %1%g filament and %2% change compared to optimal grouping.",
|
||||
"Increase %1%g filament and %2% changes compared to optimal grouping.", delta_change_to_best),
|
||||
number_format(delta_weight_to_best), delta_change_to_best);
|
||||
else if (delta_weight_to_best >= 0 && delta_change_to_best < 0)
|
||||
tip = from_u8((boost::format(_u8L("Increase %1%g filament and save %2% changes compared to optimal grouping."))
|
||||
% number_format(delta_weight_to_best)
|
||||
% std::abs(delta_change_to_best)).str());
|
||||
tip = format_wxstr(_L_PLURAL("Increase %1%g filament and save %2% change compared to optimal grouping.",
|
||||
"Increase %1%g filament and save %2% changes compared to optimal grouping.", std::abs(delta_change_to_best)),
|
||||
number_format(delta_weight_to_best), std::abs(delta_change_to_best));
|
||||
else if (delta_weight_to_best < 0 && delta_change_to_best >= 0)
|
||||
tip = from_u8((boost::format(_u8L("Save %1%g filament and increase %2% changes compared to optimal grouping."))
|
||||
% number_format(std::abs(delta_weight_to_best))
|
||||
% delta_change_to_best).str());
|
||||
tip = format_wxstr(_L_PLURAL("Save %1%g filament and increase %2% change compared to optimal grouping.",
|
||||
"Save %1%g filament and increase %2% changes compared to optimal grouping.", delta_change_to_best),
|
||||
number_format(std::abs(delta_weight_to_best)), delta_change_to_best);
|
||||
|
||||
imgui.text_wrapped(tip, parent_width);
|
||||
ImGui::PopStyleColor(1);
|
||||
@@ -3995,17 +3995,17 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
|
||||
ImGui::Dummy({window_padding, window_padding});
|
||||
wxString tip;
|
||||
if (delta_weight_to_single_ext >= 0 && delta_change_to_single_ext >= 0)
|
||||
tip = from_u8((boost::format(_u8L("Save %1%g filament and %2% changes compared to a printer with one nozzle."))
|
||||
% number_format(delta_weight_to_single_ext)
|
||||
% delta_change_to_single_ext).str());
|
||||
tip = format_wxstr(_L_PLURAL("Save %1%g filament and %2% change compared to a printer with one nozzle.",
|
||||
"Save %1%g filament and %2% changes compared to a printer with one nozzle.", delta_change_to_single_ext),
|
||||
number_format(delta_weight_to_single_ext), delta_change_to_single_ext);
|
||||
else if (delta_weight_to_single_ext >= 0 && delta_change_to_single_ext < 0)
|
||||
tip = from_u8((boost::format(_u8L("Save %1%g filament and increase %2% changes compared to a printer with one nozzle."))
|
||||
% number_format(delta_weight_to_single_ext)
|
||||
% std::abs(delta_change_to_single_ext)).str());
|
||||
tip = format_wxstr(_L_PLURAL("Save %1%g filament and increase %2% change compared to a printer with one nozzle.",
|
||||
"Save %1%g filament and increase %2% changes compared to a printer with one nozzle.", std::abs(delta_change_to_single_ext)),
|
||||
number_format(delta_weight_to_single_ext), std::abs(delta_change_to_single_ext));
|
||||
else if (delta_weight_to_single_ext < 0 && delta_change_to_single_ext >= 0)
|
||||
tip = from_u8((boost::format(_u8L("Increase %1%g filament and save %2% changes compared to a printer with one nozzle."))
|
||||
% number_format(std::abs(delta_weight_to_single_ext))
|
||||
% delta_change_to_single_ext).str());
|
||||
tip = format_wxstr(_L_PLURAL("Increase %1%g filament and save %2% change compared to a printer with one nozzle.",
|
||||
"Increase %1%g filament and save %2% changes compared to a printer with one nozzle.", delta_change_to_single_ext),
|
||||
number_format(std::abs(delta_weight_to_single_ext)), delta_change_to_single_ext);
|
||||
|
||||
imgui.text_wrapped(tip, parent_width);
|
||||
}
|
||||
|
||||
@@ -1639,7 +1639,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
|
||||
m_shortcuts_assembly_view = {
|
||||
{_L("Left mouse button"), _L("Object selection")},
|
||||
{alt + _L("Left mouse button"), _L("Part selection")},
|
||||
{"1~16 " + _L("number keys"), _L("Number keys can quickly change the color of objects")},
|
||||
{_L("1~16 number keys"), _L("Number keys can quickly change the color of objects")},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11195,7 +11195,7 @@ void GLCanvas3D::_render_paint_toolbar() const
|
||||
if (!ImGui::IsMouseHoveringRect(left_arrow_button.Min, left_arrow_button.Max) && !ImGui::IsMouseHoveringRect(right_arrow_button.Min, right_arrow_button.Max)) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 20.0f * f_scale, 10.0f * f_scale });
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f * f_scale);
|
||||
imgui.tooltip(_L("Shortcut Key ") + std::to_string(i + 1), ImGui::GetFontSize() * 20.0f);
|
||||
imgui.tooltip(wxString::Format(_L("Shortcut Key %d"), i + 1), ImGui::GetFontSize() * 20.0f);
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
}
|
||||
@@ -12086,12 +12086,9 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
extruder_name += (boost::format(_u8L("Tool %d"))%extruder_id).str();
|
||||
}
|
||||
|
||||
if (error_iter->second.size() == 1) {
|
||||
text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s.")) %filaments %extruder_name %extruder_name).str();
|
||||
}
|
||||
else {
|
||||
text += (boost::format(_u8L("Filaments %s are placed in the %s, but the generated G-code path exceeds the printable range of the %s.")) %filaments %extruder_name %extruder_name).str();
|
||||
}
|
||||
text += (boost::format(into_u8(_L_PLURAL("Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s.",
|
||||
"Filaments %s are placed in the %s, but the generated G-code path exceeds the printable range of the %s.",
|
||||
error_iter->second.size()))) %filaments %extruder_name %extruder_name).str();
|
||||
}
|
||||
error = ErrorType::SLICING_LIMIT_ERROR;
|
||||
break;
|
||||
@@ -12139,11 +12136,9 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
}
|
||||
}
|
||||
std::string extruder_name = extruder_name_list[extruder_id-1];
|
||||
if (error_iter->second.size() == 1) {
|
||||
text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s.")) % filaments % extruder_name % extruder_name).str();
|
||||
} else {
|
||||
text += (boost::format(_u8L("Filaments %s are placed in the %s, but the generated G-code path exceeds the printable height of the %s.")) % filaments % extruder_name % extruder_name).str();
|
||||
}
|
||||
text += (boost::format(into_u8(_L_PLURAL("Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s.",
|
||||
"Filaments %s are placed in the %s, but the generated G-code path exceeds the printable height of the %s.",
|
||||
filament_ids.size()))) % filaments % extruder_name % extruder_name).str();
|
||||
}
|
||||
if (!text.empty()) {
|
||||
text += "\n";
|
||||
@@ -12170,7 +12165,8 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
warning += std::to_string(filament + 1);
|
||||
warning += " ";
|
||||
}
|
||||
text = (boost::format(_u8L("Filaments %s cannot be printed directly on the surface of this plate.")) % warning).str();
|
||||
text = (boost::format(into_u8(_L_PLURAL("Filament %s cannot be printed directly on the surface of this plate.",
|
||||
"Filaments %s cannot be printed directly on the surface of this plate.", conflict_filament.size()))) % warning).str();
|
||||
error = ErrorType::SLICING_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3549,6 +3549,10 @@ bool GUI_App::on_init_inner()
|
||||
}
|
||||
|
||||
// BBS if load user preset failed
|
||||
// Let the libslic3r know the callback, which will translate messages on demand.
|
||||
// Installed before the presets load so that their load errors are translated too.
|
||||
Slic3r::I18N::set_translate_callback(libslic3r_translate_callback);
|
||||
|
||||
//if (loaded_preset_result != 0) {
|
||||
try {
|
||||
// Enable all substitutions (in both user and system profiles), but log the substitutions in user profiles only.
|
||||
@@ -3566,9 +3570,6 @@ bool GUI_App::on_init_inner()
|
||||
register_win32_device_notification_event();
|
||||
#endif // WIN32
|
||||
|
||||
// Let the libslic3r know the callback, which will translate messages on demand.
|
||||
Slic3r::I18N::set_translate_callback(libslic3r_translate_callback);
|
||||
|
||||
#if defined(__WXGTK__) && wxHAS_EGL
|
||||
// Configure GL backend before any wxGLCanvas is created.
|
||||
// On X11, prefer GLX for maximum driver compatibility.
|
||||
@@ -8582,22 +8583,23 @@ void GUI_App::refresh_plugins()
|
||||
// and report completion through the notification manager -- the speed dial needs no dialog.
|
||||
std::thread([]() {
|
||||
wxString error;
|
||||
bool unknown_error = false;
|
||||
try {
|
||||
refresh_plugin_metadata_blocking(/*fetch_cloud=*/true);
|
||||
} catch (const std::exception& ex) {
|
||||
error = from_u8(ex.what());
|
||||
} catch (...) {
|
||||
error = "Unknown error"; // plain literal: wx translation isn't safe off the UI thread
|
||||
unknown_error = true; // translated in CallAfter: wx translation isn't safe off the UI thread
|
||||
}
|
||||
if (!wxTheApp)
|
||||
return;
|
||||
wxTheApp->CallAfter([error]() {
|
||||
wxTheApp->CallAfter([error, unknown_error]() {
|
||||
if (wxGetApp().is_closing())
|
||||
return;
|
||||
Plater* plater = wxGetApp().plater();
|
||||
if (plater == nullptr)
|
||||
return;
|
||||
if (error.IsEmpty())
|
||||
if (error.IsEmpty() && !unknown_error)
|
||||
plater->get_notification_manager()->push_notification(
|
||||
NotificationType::CustomNotification,
|
||||
NotificationManager::NotificationLevel::RegularNotificationLevel,
|
||||
@@ -8606,7 +8608,7 @@ void GUI_App::refresh_plugins()
|
||||
plater->get_notification_manager()->push_notification(
|
||||
NotificationType::CustomNotification,
|
||||
NotificationManager::NotificationLevel::ErrorNotificationLevel,
|
||||
into_u8(wxString::Format(_L("Failed to refresh plugins: %s"), error)));
|
||||
into_u8(wxString::Format(_L("Failed to refresh plugins: %s"), unknown_error ? _L("Unknown error") : error)));
|
||||
});
|
||||
}).detach();
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ void GridCellFilamentsRenderer::Draw(wxGrid &grid, wxGridCellAttr &attr, wxDC &d
|
||||
dc.DrawBitmap(*bitmap, wxPoint(rect.x + offset_x, rect.y + offset_y));
|
||||
}
|
||||
else if (grid_row->model_volume_type == ModelVolumeType::PARAMETER_MODIFIER){
|
||||
dc.DrawText("Default", wxPoint(rect.x + offset_x, rect.y + offset_y));
|
||||
dc.DrawText(_L("Default"), wxPoint(rect.x + offset_x, rect.y + offset_y));
|
||||
}
|
||||
|
||||
text_rect.x += bitmap_width + grid_cell_border_width * 2;
|
||||
|
||||
@@ -818,7 +818,8 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi
|
||||
}
|
||||
|
||||
if (has_invalid_ears) {
|
||||
wxString out = _L("Warning") + ": " + std::to_string(m_single_brim.size()) + " " + _L("invalid brim ears");
|
||||
const int n_invalid = int(m_single_brim.size());
|
||||
wxString out = _L("Warning") + ": " + wxString::Format(_L_PLURAL("%d invalid brim ear", "%d invalid brim ears", n_invalid), n_invalid);
|
||||
m_imgui->text_wrapped(out, parent_width);
|
||||
}
|
||||
|
||||
|
||||
@@ -281,7 +281,6 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename,
|
||||
{"Flap Angle" , _u8L("Flap Angle")},
|
||||
{"Groove Angle" , _u8L("Groove Angle")},
|
||||
{"Cut position" , _u8L("Cut position")}, // ORCA
|
||||
{"Build Volume" , _u8L("Build Volume")}, // ORCA
|
||||
{"Multiple" , _u8L("Multiple")}, // ORCA
|
||||
{"Count" , _u8L("Count")}, // ORCA
|
||||
{"Gap" , _u8L("Gap")}, // ORCA
|
||||
@@ -2531,7 +2530,7 @@ void GLGizmoCut3D::render_build_size()
|
||||
Vec3d tbb_sz = m_transformed_bounding_box.size() * koef; // ORCA
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(_L("Build Volume"));
|
||||
m_imgui->text(_L("Size"));
|
||||
ImGui::SameLine(m_label_width);
|
||||
ImGui::Text("%.2f x %.2f x %.2f %s", tbb_sz.x(), tbb_sz.y(), tbb_sz.z(), unit_str.ToUTF8().data()); // ORCA use regular text color and simplify format
|
||||
}
|
||||
@@ -3555,10 +3554,14 @@ static void check_objects_after_cut(const ModelObjectPtrs& objects)
|
||||
wxString names = from_u8(err_objects_names[0]);
|
||||
for (size_t i = 1; i < err_objects_names.size(); i++)
|
||||
names += ", " + from_u8(err_objects_names[i]);
|
||||
WarningDialog(wxGetApp().plater(), format_wxstr(_L("Objects(%1%) have duplicated connectors. "
|
||||
WarningDialog(wxGetApp().plater(), format_wxstr(_L_PLURAL("Object (%1%) has duplicated connectors. "
|
||||
"Some connectors may be missing in slicing result.\n"
|
||||
"Please report to the OrcaSlicer team in which scenario this issue happened.\n"
|
||||
"Thank you."), names)).ShowModal();
|
||||
"Thank you.",
|
||||
"Objects (%1%) have duplicated connectors. "
|
||||
"Some connectors may be missing in slicing result.\n"
|
||||
"Please report to the OrcaSlicer team in which scenario this issue happened.\n"
|
||||
"Thank you.", unsigned(err_objects_names.size())), names)).ShowModal();
|
||||
}
|
||||
|
||||
void synchronize_model_after_cut(Model& model, const CutObjectBase& cut_id)
|
||||
|
||||
@@ -898,9 +898,9 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
||||
|
||||
// Not known situation when could happend this is only for sure
|
||||
if (!m_is_unknown_font && !m_style_manager.is_active_font())
|
||||
create_notification_not_valid_font("No active font in style. Select correct one.");
|
||||
create_notification_not_valid_font(_u8L("No active font in style. Select correct one."));
|
||||
else if (!m_is_unknown_font && !m_style_manager.get_wx_font().IsOk())
|
||||
create_notification_not_valid_font("WxFont is not loaded properly.");
|
||||
create_notification_not_valid_font(_u8L("WxFont is not loaded properly."));
|
||||
|
||||
double screen_scale = wxDisplay(wxGetApp().plater()).GetScaleFactor();
|
||||
|
||||
|
||||
@@ -1912,13 +1912,13 @@ void GLGizmoMeasure::show_selection_ui()
|
||||
float selection_cap_length = 0;
|
||||
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY) {
|
||||
if (m_assembly_mode == AssemblyMode::FACE_FACE) {
|
||||
selection_cap_length = ImGui::CalcTextSize((_u8L("Selection") + " 1" + _u8L(" (Moving)")).c_str()).x * 1.2;
|
||||
selection_cap_length = std::max(ImGui::CalcTextSize(_u8L("Face 1 (Fixed)").c_str()).x, ImGui::CalcTextSize(_u8L("Face 2 (Moving)").c_str()).x) * 1.2;
|
||||
} else if (m_assembly_mode == AssemblyMode::POINT_POINT) {
|
||||
selection_cap_length = ImGui::CalcTextSize((_u8L("Selection") + " 1" + _u8L(" (Moving)")).c_str()).x * 1.2;
|
||||
selection_cap_length = std::max(ImGui::CalcTextSize(_u8L("Point 1 (Fixed)").c_str()).x, ImGui::CalcTextSize(_u8L("Point 2 (Moving)").c_str()).x) * 1.2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
selection_cap_length = ImGui::CalcTextSize((_u8L("Selection") + " 1").c_str()).x * 1.2;
|
||||
selection_cap_length = ImGui::CalcTextSize(_u8L("Selection 1").c_str()).x * 1.2;
|
||||
}
|
||||
auto feature_first_text = format_item_text(m_selected_features.first);
|
||||
const float feature_first_text_length = ImGui::CalcTextSize((_u8L(feature_first_text)).c_str()).x;
|
||||
@@ -1934,13 +1934,13 @@ void GLGizmoMeasure::show_selection_ui()
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR));
|
||||
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY) {
|
||||
if (m_assembly_mode == AssemblyMode::FACE_FACE) {
|
||||
m_imgui->text(_u8L("Face") + " 1" + _u8L(" (Fixed)"));
|
||||
m_imgui->text(_u8L("Face 1 (Fixed)"));
|
||||
} else if (m_assembly_mode == AssemblyMode::POINT_POINT) {
|
||||
m_imgui->text(_u8L("Point") + " 1" + _u8L(" (Fixed)"));
|
||||
m_imgui->text(_u8L("Point 1 (Fixed)"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_imgui->text(_u8L("Selection") + " 1");
|
||||
m_imgui->text(_u8L("Selection 1"));
|
||||
}
|
||||
ImGui::SameLine(selection_cap_length + space_size);
|
||||
ImGui::PushItemWidth(feature_first_text_length);
|
||||
@@ -1960,12 +1960,12 @@ void GLGizmoMeasure::show_selection_ui()
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR));
|
||||
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY) {
|
||||
if (m_assembly_mode == AssemblyMode::FACE_FACE) {
|
||||
m_imgui->text(_u8L("Face") + " 2"+ _u8L(" (Moving)"));
|
||||
m_imgui->text(_u8L("Face 2 (Moving)"));
|
||||
} else if (m_assembly_mode == AssemblyMode::POINT_POINT) {
|
||||
m_imgui->text(_u8L("Point") + " 2"+ _u8L(" (Moving)"));
|
||||
m_imgui->text(_u8L("Point 2 (Moving)"));
|
||||
}
|
||||
} else {
|
||||
m_imgui->text(_u8L("Selection") + " 2");
|
||||
m_imgui->text(_u8L("Selection 2"));
|
||||
}
|
||||
ImGui::SameLine(selection_cap_length + space_size);
|
||||
ImGui::PushItemWidth(feature_second_text_length);
|
||||
|
||||
@@ -248,7 +248,7 @@ void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_l
|
||||
ImGui::CalcTextSize(_u8L("Subtract from").c_str()).x,
|
||||
ImGui::CalcTextSize(_u8L("Subtract with").c_str()).x});
|
||||
|
||||
const int select_btn_length = 2 * ImGui::GetStyle().FramePadding.x + std::max(ImGui::CalcTextSize(("1 " + _u8L("selected")).c_str()).x, ImGui::CalcTextSize(_u8L("Select").c_str()).x);
|
||||
const int select_btn_length = 2 * ImGui::GetStyle().FramePadding.x + std::max(ImGui::CalcTextSize(_u8L("1 selected").c_str()).x, ImGui::CalcTextSize(_u8L("Select").c_str()).x);
|
||||
|
||||
auto selectable = [](const std::string& label, bool selected, const ImVec2& size_arg) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0,0 });
|
||||
@@ -323,7 +323,8 @@ void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_l
|
||||
std::string cap_str1 = m_operation_mode != MeshBooleanOperation::Difference ? _u8L("Part 1") : _u8L("Subtract from");
|
||||
m_imgui->text(cap_str1);
|
||||
ImGui::SameLine(max_cap_length);
|
||||
std::string select_src_str = m_src.mv ? "1 " + _u8L("selected") : _u8L("Select");
|
||||
// TRN Mesh Boolean button label once one volume is picked.
|
||||
std::string select_src_str = m_src.mv ? _u8L("1 selected") : _u8L("Select");
|
||||
select_src_str += "##select_source_volume";
|
||||
ImGui::PushItemWidth(select_btn_length);
|
||||
if (selectable(select_src_str, m_selecting_state == MeshBooleanSelectingState::SelectSource, ImVec2(select_btn_length, 0)))
|
||||
@@ -351,7 +352,7 @@ void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_l
|
||||
std::string cap_str2 = m_operation_mode != MeshBooleanOperation::Difference ? _u8L("Part 2") : _u8L("Subtract with");
|
||||
m_imgui->text(cap_str2);
|
||||
ImGui::SameLine(max_cap_length);
|
||||
std::string select_tool_str = m_tool.mv ? "1 " + _u8L("selected") : _u8L("Select");
|
||||
std::string select_tool_str = m_tool.mv ? _u8L("1 selected") : _u8L("Select");
|
||||
select_tool_str += "##select_tool_volume";
|
||||
ImGui::PushItemWidth(select_btn_length);
|
||||
if (selectable(select_tool_str, m_selecting_state == MeshBooleanSelectingState::SelectTool, ImVec2(select_btn_length, 0)))
|
||||
|
||||
@@ -56,8 +56,12 @@ static inline void show_notification_extruders_limit_exceeded()
|
||||
.plater()
|
||||
->get_notification_manager()
|
||||
->push_notification(NotificationType::MmSegmentationExceededExtrudersLimit, NotificationManager::NotificationLevel::PrintInfoNotificationLevel,
|
||||
GUI::format(_L("Filament count exceeds the maximum number that painting tool supports. Only the "
|
||||
"first %1% filaments will be available in painting tool."), GLGizmoMmuSegmentation::EXTRUDERS_LIMIT));
|
||||
GUI::format(_L_PLURAL("Filament count exceeds the maximum number that painting tool supports. Only the "
|
||||
"first %1% filament will be available in painting tool.",
|
||||
"Filament count exceeds the maximum number that painting tool supports. Only the "
|
||||
"first %1% filaments will be available in painting tool.",
|
||||
unsigned(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)),
|
||||
GLGizmoMmuSegmentation::EXTRUDERS_LIMIT));
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::on_opening()
|
||||
@@ -459,7 +463,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
m_selected_extruder_idx = extruder_idx;
|
||||
}
|
||||
|
||||
if (extruder_idx < int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT) && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width);
|
||||
if (extruder_idx < int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT) && ImGui::IsItemHovered()) m_imgui->tooltip(wxString::Format(_L("Shortcut Key %d"), extruder_idx + 1), max_tooltip_width);
|
||||
}
|
||||
// ORCA: Remap filaments section (Border only, Title in border).
|
||||
// Styled as a panel for visual grouping.
|
||||
|
||||
@@ -355,7 +355,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::SameLine(bottom_left_width + space_size);
|
||||
ImGui::Text(_u8L("%d triangles").c_str(), m_configuration.wanted_count);
|
||||
ImGui::TextUnformatted(GUI::format(_L_PLURAL("%1% triangle", "%1% triangles", m_configuration.wanted_count), m_configuration.wanted_count).c_str());
|
||||
m_imgui->disabled_end(); // use_count
|
||||
|
||||
m_imgui->bbl_checkbox(_L("Show wireframe").c_str(), m_show_wireframe);
|
||||
|
||||
@@ -6530,7 +6530,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
|
||||
ImGui::AlignTextToFramePadding();
|
||||
heading(_L("Texture displacement"));
|
||||
|
||||
const std::string labels[2] = { _u8L("Standard"), _u8L("Pro") };
|
||||
const std::string labels[2] = { _u8L_CONTEXT("Standard", "Mode"), _u8L("Pro") };
|
||||
const float seg_pad = m_imgui->scaled(0.5f);
|
||||
const float seg_w[2] = { ImGui::CalcTextSize(labels[0].c_str()).x + 2.f * seg_pad, ImGui::CalcTextSize(labels[1].c_str()).x + 2.f * seg_pad };
|
||||
ImGui::SameLine();
|
||||
@@ -7145,8 +7145,13 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
|
||||
"texture's colors, and only the ones the bake actually uses are created.")))
|
||||
m_preview_params_dirty = true;
|
||||
// After the slider, so a change shows in the same frame.
|
||||
ImGui::TextDisabled("%s", Slic3r::format(_u8L("%1% printable colors from %2% filaments"),
|
||||
int(cached_palette().size()), int(m_palette_filaments.size())).c_str());
|
||||
const int n_colors = int(cached_palette().size());
|
||||
const int n_filaments = int(m_palette_filaments.size());
|
||||
// TRN The %2% part of "%1% printable colors %2%"; %1% is the number of filaments.
|
||||
const std::string from_filaments = Slic3r::format(into_u8(_L_PLURAL("from %1% filament", "from %1% filaments", n_filaments)), n_filaments);
|
||||
// TRN %1% is the number of printable colors, %2% is "from N filaments".
|
||||
ImGui::TextDisabled("%s", Slic3r::format(into_u8(_L_PLURAL("%1% printable color %2%", "%1% printable colors %2%", n_colors)),
|
||||
n_colors, from_filaments).c_str());
|
||||
}
|
||||
if (int_row("##color_despeckle", _L("Denoise"), &opts.color_despeckle, 0, 6, "%d", card_pad,
|
||||
_L("Cleans up single stray triangles of the wrong color, which detail finer "
|
||||
@@ -7233,7 +7238,8 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
|
||||
if (m_uv_editor_unwrap.empty())
|
||||
ImGui::TextDisabled("%s", _u8L("Not unwrapped yet").c_str());
|
||||
else
|
||||
ImGui::TextDisabled("%s", Slic3r::format(_u8L("%1% islands"), m_uv_editor_unwrap.chart_count).c_str());
|
||||
ImGui::TextDisabled("%s", Slic3r::format(into_u8(_L_PLURAL("%1% island", "%1% islands", m_uv_editor_unwrap.chart_count)),
|
||||
m_uv_editor_unwrap.chart_count).c_str());
|
||||
}
|
||||
|
||||
if (layer.projection_method == TextureProjectionMethod::ViewProjected) {
|
||||
@@ -7535,7 +7541,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
|
||||
|
||||
if (mv != nullptr) {
|
||||
const bool full = mv->texture_displacement_layers.size() >= TEXTURE_DISPLACEMENT_MAX_LAYERS;
|
||||
const std::string label = full ? Slic3r::format(_u8L("All %1% layers used"), TEXTURE_DISPLACEMENT_MAX_LAYERS) :
|
||||
const std::string label = full ? Slic3r::format(into_u8(_L_PLURAL("All %1% layer used", "All %1% layers used", unsigned(TEXTURE_DISPLACEMENT_MAX_LAYERS))), TEXTURE_DISPLACEMENT_MAX_LAYERS) :
|
||||
"+ " + _u8L("Add layer");
|
||||
m_imgui->disabled_begin(busy || full);
|
||||
if (ImGui::Button((label + "##add_layer").c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0.f)))
|
||||
@@ -7631,7 +7637,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
|
||||
|
||||
ImGui::TextDisabled("%s", _u8L("Triangle budget: set with Triangles, below.").c_str());
|
||||
if (m_subdivide_editing && m_subdivide_preview_tris > 0)
|
||||
m_imgui->text(Slic3r::format(_u8L("Preview: %1% triangles"), m_subdivide_preview_tris));
|
||||
m_imgui->text(Slic3r::format(into_u8(_L_PLURAL("Preview: %1% triangle", "Preview: %1% triangles", m_subdivide_preview_tris)), m_subdivide_preview_tris));
|
||||
} else {
|
||||
if (int_row("##subdiv_steps", _L("Steps"), &m_subdivide_count, 0, 5, "%d", 0.f,
|
||||
_L("Splits every triangle of the model into four, this many times over. Each step "
|
||||
@@ -8059,18 +8065,28 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float
|
||||
if (mv != nullptr) {
|
||||
const std::string base_count = base_k > 0 ? Slic3r::format(_u8L("%1% k"), base_k) :
|
||||
std::to_string(mv->mesh().facets_count());
|
||||
std::string note = v2 ? Slic3r::format(_u8L("Model: %1% triangles - the bake refines to the resolution above, up to its budget"), base_count) :
|
||||
pro_mode() ? Slic3r::format(_u8L("Bake moves existing vertices - the model stays at %1% triangles"), base_count) :
|
||||
Slic3r::format(_u8L("Bake result up to ~%1% k triangles"), base_k + m_subdivide_budget_k);
|
||||
const unsigned base_n = base_k > 0 ? unsigned(base_k) * 1000 : unsigned(mv->mesh().facets_count());
|
||||
const unsigned result_n = unsigned(base_k + m_subdivide_budget_k) * 1000;
|
||||
// TRN %1% is a triangle count, either exact or rounded to thousands such as "120 k".
|
||||
std::string note = v2 ? Slic3r::format(into_u8(_L_PLURAL("Model: %1% triangle - the bake refines to the resolution above, up to its budget",
|
||||
"Model: %1% triangles - the bake refines to the resolution above, up to its budget", base_n)), base_count) :
|
||||
// TRN %1% is a triangle count, either exact or rounded to thousands such as "120 k".
|
||||
pro_mode() ? Slic3r::format(into_u8(_L_PLURAL("Bake moves existing vertices - the model stays at %1% triangle",
|
||||
"Bake moves existing vertices - the model stays at %1% triangles", base_n)), base_count) :
|
||||
Slic3r::format(into_u8(_L_PLURAL("Bake result up to ~%1% k triangle", "Bake result up to ~%1% k triangles", result_n)),
|
||||
base_k + m_subdivide_budget_k);
|
||||
if (mv->is_texture_displacement_painted()) {
|
||||
std::vector<std::string> skipped;
|
||||
for (const TextureDisplacementLayer &l : mv->texture_displacement_layers)
|
||||
if (!slot_painted(l.slot))
|
||||
skipped.push_back(layer_name(l));
|
||||
if (skipped.size() > 2)
|
||||
note += ", " + Slic3r::format(_u8L("%1% layers not painted, skipped"), skipped.size());
|
||||
note += ", " + Slic3r::format(into_u8(_L_PLURAL("%1% layer not painted, skipped", "%1% layers not painted, skipped",
|
||||
unsigned(skipped.size()))), skipped.size());
|
||||
else if (!skipped.empty())
|
||||
note += ", " + Slic3r::format(_u8L("%1% not painted, skipped"),
|
||||
// TRN %1% is one layer name, or two names separated by a comma.
|
||||
note += ", " + Slic3r::format(into_u8(_L_PLURAL("%1% not painted, skipped", "%1% not painted, skipped",
|
||||
unsigned(skipped.size()))),
|
||||
skipped.size() == 2 ? skipped[0] + ", " + skipped[1] : skipped[0]);
|
||||
}
|
||||
ImGui::PushTextWrapPos(x0 + panel_w);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "slic3r/GUI/BitmapComboBox.hpp"
|
||||
#include "slic3r/GUI/PartPlate.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
@@ -95,7 +96,7 @@ void IMEXFilamentPickerPopover::build_row()
|
||||
};
|
||||
|
||||
for (int L : lane_logicals) {
|
||||
const wxString label = wxString::Format("filament %d", L + 1);
|
||||
const wxString label = wxString::Format(_L("Filament %d"), L + 1);
|
||||
if (L >= 0 && L < (int)bmps.size() && bmps[L] && bmps[L]->IsOk())
|
||||
choice->Append(label, pad_left(*bmps[L]));
|
||||
else
|
||||
|
||||
@@ -321,15 +321,21 @@ bool IMEXModesCtrl::fix_row_name(Row& r) {
|
||||
IMEXModesCtrl::RoleStyle IMEXModesCtrl::role_style(std::optional<ImexRole> role) {
|
||||
// Gray / "Inactive" is the no-role answer; every role gets an explicit case so a new
|
||||
// one is a compile-time -Wswitch prompt rather than a tile that silently renders gray.
|
||||
// TRN IDEX/IQEX role of a tool head that takes no part in the mode.
|
||||
const wxString inactive = _L_CONTEXT("Inactive", "IDEX/IQEX role");
|
||||
if (!role)
|
||||
return { wxColour(90, 90, 90), *wxWHITE, "Inactive" };
|
||||
return { wxColour(90, 90, 90), *wxWHITE, inactive };
|
||||
switch (*role) {
|
||||
case ImexRole::Primary: return { wxColour(50, 160, 50), *wxWHITE, "Primary" }; // green
|
||||
case ImexRole::Copy: return { wxColour(60, 120, 210), *wxWHITE, "Copy" }; // blue
|
||||
case ImexRole::Mirror: return { wxColour(210, 130, 20), *wxWHITE, "Mirror" }; // amber
|
||||
case ImexRole::Span: return { wxColour(180, 180, 40), *wxWHITE, "Span" }; // yellow
|
||||
// TRN IDEX/IQEX role: the tool head the slicer generates paths for.
|
||||
case ImexRole::Primary: return { wxColour(50, 160, 50), *wxWHITE, _L_CONTEXT("Primary", "IDEX/IQEX role") }; // green
|
||||
// TRN IDEX/IQEX role: the tool head prints a copy of the Primary's paths.
|
||||
case ImexRole::Copy: return { wxColour(60, 120, 210), *wxWHITE, _L_CONTEXT("Copy", "IDEX/IQEX role") }; // blue
|
||||
// TRN IDEX/IQEX role: the tool head prints a mirror image of the Primary's paths.
|
||||
case ImexRole::Mirror: return { wxColour(210, 130, 20), *wxWHITE, _L_CONTEXT("Mirror", "IDEX/IQEX role") }; // amber
|
||||
// TRN IDEX/IQEX role: multicolor partner of the Primary on the same gantry.
|
||||
case ImexRole::Span: return { wxColour(180, 180, 40), *wxWHITE, _L_CONTEXT("Span", "IDEX/IQEX role") }; // yellow
|
||||
}
|
||||
return { wxColour(90, 90, 90), *wxWHITE, "Inactive" }; // keeps every compiler quiet
|
||||
return { wxColour(90, 90, 90), *wxWHITE, inactive }; // keeps every compiler quiet
|
||||
}
|
||||
|
||||
wxString IMEXModesCtrl::role_hint(ImexRole role) {
|
||||
|
||||
@@ -147,9 +147,8 @@ private:
|
||||
|
||||
// Everything the editor draws for one role, in ONE place: a new role needs a color and
|
||||
// a legend name here and nowhere else in this file. nullopt is Inactive (gray).
|
||||
// `label` is deliberately untranslated — it names a role, and the legend sits next to
|
||||
// the same letters the preset stores.
|
||||
struct RoleStyle { wxColour bg; wxColour fg; const char* label; };
|
||||
// `label` is display-only and translated; the preset stores the role letters, never it.
|
||||
struct RoleStyle { wxColour bg; wxColour fg; wxString label; };
|
||||
static RoleStyle role_style(std::optional<ImexRole> role);
|
||||
|
||||
// True when this printer offers `role` at all, regardless of which tile is clicked.
|
||||
|
||||
@@ -1564,7 +1564,7 @@ void IMSlider::render_add_menu()
|
||||
ImU32 icon_clr = ImGuiWrapper::to_ImU32(rgba);
|
||||
if (rgba.a() == 0)
|
||||
icon_clr = 0;
|
||||
if (menu_item_with_icon((_u8L("Filament ") + std::to_string(i + 1)).c_str(), "", ImVec2(14, 14) * m_scale, icon_clr, false, true, &hovered)) add_code_as_tick(ToolChange, i + 1);
|
||||
if (menu_item_with_icon(into_u8(wxString::Format(_L("Filament %d"), i + 1)).c_str(), "", ImVec2(14, 14) * m_scale, icon_clr, false, true, &hovered)) add_code_as_tick(ToolChange, i + 1);
|
||||
if (hovered) { show_tooltip(_u8L("Change filament at the beginning of this layer.")); }
|
||||
}
|
||||
end_menu();
|
||||
@@ -1614,7 +1614,7 @@ void IMSlider::render_edit_menu(const TickCode& tick)
|
||||
for (int i = 0; i < extruder_num; i++) {
|
||||
ColorRGBA rgba = decode_color_to_float_array(m_extruder_colors[i]);
|
||||
ImU32 icon_clr = ImGuiWrapper::to_ImU32(rgba);
|
||||
if (menu_item_with_icon((_u8L("Filament ") + std::to_string(i + 1)).c_str(), "", ImVec2(14, 14) * m_scale, icon_clr)) add_code_as_tick(ToolChange, i + 1);
|
||||
if (menu_item_with_icon(into_u8(wxString::Format(_L("Filament %d"), i + 1)).c_str(), "", ImVec2(14, 14) * m_scale, icon_clr)) add_code_as_tick(ToolChange, i + 1);
|
||||
}
|
||||
end_menu();
|
||||
}
|
||||
|
||||
@@ -647,7 +647,7 @@ void ArrangeJob::check_unprintable()
|
||||
if (it->poly.area() < 0.001) {
|
||||
auto msg = (boost::format(
|
||||
_u8L("Object %s has zero size and can't be arranged."))
|
||||
% _utf8(it->name)).str();
|
||||
% it->name).str();
|
||||
m_plater->get_notification_manager()->push_notification(NotificationType::BBLPlateInfo,
|
||||
NotificationManager::NotificationLevel::WarningNotificationLevel, msg);
|
||||
}
|
||||
@@ -693,7 +693,8 @@ void ArrangeJob::process(Ctl &ctl)
|
||||
params.stopcondition = [&ctl]() { return ctl.was_canceled(); };
|
||||
|
||||
params.progressind = [this, &ctl](unsigned num_finished, std::string str = "") {
|
||||
ctl.update_status(num_finished * 100 / status_range(), _u8L("Arranging ") + str);
|
||||
// TRN Progress status. %1% is the name of the object being arranged.
|
||||
ctl.update_status(num_finished * 100 / status_range(), GUI::format(_u8L("Arranging %1%"), str));
|
||||
};
|
||||
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/GUI/PartPlate.hpp"
|
||||
#include "slic3r/GUI/Selection.hpp"
|
||||
|
||||
@@ -265,9 +266,10 @@ void FillBedJob::process(Ctl &ctl)
|
||||
return ctl.was_canceled() || do_stop;
|
||||
};
|
||||
|
||||
params.progressind = [this, &ctl, &statustxt](unsigned st,std::string str="") {
|
||||
params.progressind = [this, &ctl](unsigned st,std::string str="") {
|
||||
if (st > 0)
|
||||
ctl.update_status(st * 100 / status_range(), statustxt + " " + str);
|
||||
// TRN Progress status of Fill bed. %1% is the name of the object being copied.
|
||||
ctl.update_status(st * 100 / status_range(), GUI::format(_u8L("Filling %1%"), str));
|
||||
};
|
||||
|
||||
params.on_packed = [&do_stop] (const ArrangePolygon &ap) {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/GUI/Selection.hpp"
|
||||
|
||||
|
||||
@@ -235,7 +236,8 @@ void OrientJob::process(Ctl &ctl)
|
||||
|
||||
params.progressind = [this, count, &ctl](unsigned st, std::string orientstr) {
|
||||
st += m_unprintable.size();
|
||||
if (st > 0) ctl.update_status(int(st / float(count) * 100), _u8L("Orienting") + " " + orientstr);
|
||||
// TRN Progress status. %1% is the name of the object being oriented.
|
||||
if (st > 0) ctl.update_status(int(st / float(count) * 100), GUI::format(_u8L("Orienting %1%"), orientstr));
|
||||
};
|
||||
|
||||
orientation::orient(m_selected, m_unselected, params);
|
||||
|
||||
@@ -104,7 +104,7 @@ class PlaterWorker: public Worker {
|
||||
if (eptr) try {
|
||||
std::rethrow_exception(eptr);
|
||||
} catch (std::exception &e) {
|
||||
show_error(m_plater, _L("An unexpected error occurred") + ": " + e.what());
|
||||
show_error(m_plater, _L("An unexpected error occurred") + ": " + from_u8(e.what()));
|
||||
eptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,13 +34,13 @@ class SLAImportDialog : public wxDialog, public SLAImportJobView
|
||||
wxComboBox *m_import_dropdown, *m_quality_dropdown;
|
||||
|
||||
public:
|
||||
SLAImportDialog(Plater *plater) : wxDialog{plater, wxID_ANY, "Import SLA archive"}
|
||||
SLAImportDialog(Plater *plater) : wxDialog{plater, wxID_ANY, _L("Import SLA archive")}
|
||||
{
|
||||
auto szvert = new wxBoxSizer{wxVERTICAL};
|
||||
auto szfilepck = new wxBoxSizer{wxHORIZONTAL};
|
||||
|
||||
m_filepicker = new wxFilePickerCtrl(this, wxID_ANY, from_u8(wxGetApp().app_config->get_last_dir()), _(L("Choose SLA archive:")),
|
||||
"SL1 / SL1S archive files (*.sl1, *.sl1s, *.zip)|*.sl1;*.SL1;*.sl1s;*.SL1S;*.zip;*.ZIP",
|
||||
_L("SL1 / SL1S archive files") + " (*.sl1, *.sl1s, *.zip)|*.sl1;*.SL1;*.sl1s;*.SL1S;*.zip;*.ZIP",
|
||||
wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE | wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
|
||||
szfilepck->Add(new wxStaticText(this, wxID_ANY, _L("Import file") + ": "), 0, wxALIGN_CENTER);
|
||||
|
||||
@@ -76,7 +76,7 @@ void SLAImportJob::process(Ctl &ctl)
|
||||
break;
|
||||
}
|
||||
} catch (MissingProfileError &) {
|
||||
p->err = _L("The SLA archive doesn\'t contain any presets. Please activate some SLA printer presets first before importing that SLA archive.").ToStdString();
|
||||
p->err = _u8L("The SLA archive doesn\'t contain any presets. Please activate some SLA printer presets first before importing that SLA archive.");
|
||||
} catch (std::exception &ex) {
|
||||
p->err = ex.what();
|
||||
}
|
||||
@@ -124,8 +124,8 @@ void SLAImportJob::finalize(bool canceled, std::exception_ptr &eptr)
|
||||
p->plater->get_notification_manager()->push_notification(
|
||||
NotificationType::CustomNotification,
|
||||
NotificationManager::NotificationLevel::WarningNotificationLevel,
|
||||
_L("The imported SLA archive did not contain any presets. "
|
||||
"The current SLA presets were used as fallback.").ToStdString());
|
||||
_u8L("The imported SLA archive did not contain any presets. "
|
||||
"The current SLA presets were used as fallback."));
|
||||
}
|
||||
|
||||
if (p->sel != Sel::modelOnly) {
|
||||
|
||||
@@ -1746,7 +1746,8 @@ bool MainFrame::preview_only_hint()
|
||||
confirm_dlg.update_btn_label(_L("Yes"), _L("No"));
|
||||
auto filename = m_plater->get_preview_only_filename();
|
||||
|
||||
confirm_dlg.update_text(filename + " " + _L("will be closed before creating a new model. Do you want to continue?"));
|
||||
// TRN %s is a file name.
|
||||
confirm_dlg.update_text(wxString::Format(_L("%s will be closed before creating a new model. Do you want to continue?"), from_u8(filename)));
|
||||
confirm_dlg.on_show();
|
||||
if (preview_only_to_editor) {
|
||||
m_plater->new_project();
|
||||
|
||||
@@ -144,7 +144,7 @@ wxString DeviceItem::get_state_device()
|
||||
str_state_device.push_back(_L("Printing Failed"));
|
||||
str_state_device.push_back(_L("Printing"));
|
||||
str_state_device.push_back(_L("Printing Pause"));
|
||||
str_state_device.push_back(_L("Prepare"));
|
||||
str_state_device.push_back(_L_CONTEXT("Prepare", "Device status"));
|
||||
str_state_device.push_back(_L("Slicing"));
|
||||
str_state_device.push_back(_L("Syncing"));
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "MultiMachineManagerPage.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
|
||||
#include "DeviceCore/DevManager.h"
|
||||
@@ -253,7 +254,7 @@ void MultiMachineItem::doRender(wxDC& dc)
|
||||
dc.DrawRoundedRectangle(left, (size.y - FromDIP(38)) / 2, FromDIP(90), FromDIP(38), 6);
|
||||
dc.SetFont(Label::Body_14);
|
||||
dc.SetTextForeground(*wxBLACK);
|
||||
dc.DrawText(_L("View"),left + FromDIP(90) / 2 - dc.GetTextExtent(_L("View")).x / 2, (size.y -dc.GetTextExtent(_L("View")).y) / 2);
|
||||
dc.DrawText(_L_CONTEXT("View", "Verb"),left + FromDIP(90) / 2 - dc.GetTextExtent(_L_CONTEXT("View", "Verb")).x / 2, (size.y -dc.GetTextExtent(_L_CONTEXT("View", "Verb")).y) / 2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ MultiTaskItem::MultiTaskItem(wxWindow* parent, MachineObject* obj, int type)
|
||||
m_button_cancel->SetCornerRadius(6);
|
||||
m_button_cancel->SetMinSize(wxSize(FromDIP(70), FromDIP(35)));
|
||||
|
||||
m_button_pause = new Button(this, _L("Pause"));
|
||||
m_button_pause = new Button(this, _L_CONTEXT("Pause", "Verb"));
|
||||
m_button_pause->SetBackgroundColor(clean_bg);
|
||||
m_button_pause->SetBorderColor(clean_bd);
|
||||
m_button_pause->SetTextColor(clean_text);
|
||||
@@ -1193,7 +1193,7 @@ CloudTaskManagerPage::CloudTaskManagerPage(wxWindow* parent)
|
||||
m_ctrl_btn_panel->SetMinSize(wxSize(FromDIP(CLOUD_TASK_ITEM_MAX_WIDTH), -1));
|
||||
m_ctrl_btn_panel->SetMaxSize(wxSize(FromDIP(CLOUD_TASK_ITEM_MAX_WIDTH), -1));
|
||||
m_btn_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
btn_pause_all = new Button(m_ctrl_btn_panel, _L("Pause"));
|
||||
btn_pause_all = new Button(m_ctrl_btn_panel, _L_CONTEXT("Pause", "Verb"));
|
||||
btn_pause_all->SetBackgroundColor(ctrl_bg);
|
||||
btn_pause_all->SetCornerRadius(FromDIP(5));
|
||||
btn_continue_all = new Button(m_ctrl_btn_panel, _L("Resume"));
|
||||
|
||||
@@ -2147,13 +2147,6 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id)
|
||||
std::string cur = get_imex_mode();
|
||||
const std::string effective = get_effective_imex_mode();
|
||||
if (cur == kImexPrimaryMode) cur = _u8L("Primary");
|
||||
if (effective != get_imex_mode()) {
|
||||
try {
|
||||
cur += (boost::format(_u8L(" (process preset: %1%)")) % effective).str();
|
||||
} catch (const std::exception&) {
|
||||
cur += (boost::format(" (process preset: %1%)") % effective).str();
|
||||
}
|
||||
}
|
||||
// One format string, not two catalog fragments concatenated around a
|
||||
// runtime value: translators need to move the mode name within the
|
||||
// sentence, and the space-padded fragments were untranslatable alone.
|
||||
@@ -2162,10 +2155,19 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id)
|
||||
// TRANSLATED string drops or malforms %1%, and an exception escaping here
|
||||
// would take down the frame rather than show a wrong tooltip. The English
|
||||
// literal is the fallback and cannot itself throw.
|
||||
try {
|
||||
hover_tip = (boost::format(_u8L("IDEX/IQEX mode: %1% (left-click to cycle, right-click for menu)")) % cur).str();
|
||||
} catch (const std::exception&) {
|
||||
hover_tip = (boost::format("IDEX/IQEX mode: %1% (left-click to cycle, right-click for menu)") % cur).str();
|
||||
if (effective != get_imex_mode()) {
|
||||
try {
|
||||
// TRN Plate icon tooltip. %1% is the plate's IDEX/IQEX mode, %2% the mode its process preset sets.
|
||||
hover_tip = (boost::format(_u8L("IDEX/IQEX mode: %1% (process preset: %2%) (left-click to cycle, right-click for menu)")) % cur % effective).str();
|
||||
} catch (const std::exception&) {
|
||||
hover_tip = (boost::format("IDEX/IQEX mode: %1% (process preset: %2%) (left-click to cycle, right-click for menu)") % cur % effective).str();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
hover_tip = (boost::format(_u8L("IDEX/IQEX mode: %1% (left-click to cycle, right-click for menu)")) % cur).str();
|
||||
} catch (const std::exception&) {
|
||||
hover_tip = (boost::format("IDEX/IQEX mode: %1% (left-click to cycle, right-click for menu)") % cur).str();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
render_icon_texture(m_imex_mode_icon.model, m_partplate_list->m_imex_mode_textures[kind]);
|
||||
@@ -3034,8 +3036,8 @@ bool PartPlate::check_filament_printable(const DynamicPrintConfig &config, wxStr
|
||||
int filament_printable_status = filament_printables[filament_id];
|
||||
int extruder_idx = filament_map[filament_id] - 1;
|
||||
if (!(filament_printable_status >> extruder_idx & 1)) {
|
||||
wxString extruder_name = extruder_idx == 0 ? _L("left") : _L("right");
|
||||
error_message = wxString::Format(_L("The %s nozzle can not print %s."), extruder_name, filament_type);
|
||||
error_message = wxString::Format(extruder_idx == 0 ? _L("The left nozzle cannot print %s.") : _L("The right nozzle cannot print %s."),
|
||||
filament_type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -3228,9 +3230,8 @@ bool PartPlate::check_compatible_of_nozzle_and_filament(const DynamicPrintConfig
|
||||
auto get_nozzle_msg = [](const float nozzle_diameter, const NozzleVolumeType volume_type) -> std::string {
|
||||
std::ostringstream oss;
|
||||
oss << std::fixed << std::setprecision(1) << nozzle_diameter;
|
||||
std::string nozzle_msg = oss.str();
|
||||
((nozzle_msg += "mm ") += _u8L(get_nozzle_volume_type_string(volume_type))) += _u8L(" nozzle");
|
||||
return nozzle_msg;
|
||||
// TRN %1% is the nozzle diameter, %2% the nozzle volume type, for example "Standard" or "High Flow".
|
||||
return Slic3r::format(_u8L("%1%mm %2% nozzle"), oss.str(), _u8L(get_nozzle_volume_type_string(volume_type)));
|
||||
};
|
||||
|
||||
auto get_incompatible_filament_msg = [](const std::set<std::string> &incompatible_selected_filaments) -> std::string {
|
||||
@@ -3261,7 +3262,9 @@ bool PartPlate::check_compatible_of_nozzle_and_filament(const DynamicPrintConfig
|
||||
auto elem = incompatible_selected_map.begin();
|
||||
NozzleVolumeType volume_type = elem->first;
|
||||
auto incompatible_selected = elem->second;
|
||||
error_msg = GUI::format(_L("It is not recommended to print the following filament(s) with %1%: %2%\n"), get_nozzle_msg(nozzle_diameter, volume_type),
|
||||
error_msg = GUI::format(_L_PLURAL("It is not recommended to print the following filament with %1%: %2%\n",
|
||||
"It is not recommended to print the following filaments with %1%: %2%\n", incompatible_selected.size()),
|
||||
get_nozzle_msg(nozzle_diameter, volume_type),
|
||||
get_incompatible_filament_msg(incompatible_selected));
|
||||
} else {
|
||||
std::string warning_msg = _u8L("It is not recommended to use the following nozzle and filament combinations:\n");
|
||||
@@ -4669,8 +4672,8 @@ void PartPlate::update_slice_context(BackgroundSlicingProcess & process)
|
||||
Slic3r::SlicingStatusEvent *event = new Slic3r::SlicingStatusEvent(EVT_SLICING_UPDATE, 0, status);
|
||||
//BBS: GUI refactor: add plate info befor message
|
||||
if (status.message_type == Slic3r::PrintStateBase::SlicingDefaultNotification) {
|
||||
auto temp = Slic3r::format(_u8L(" plate %1%:"), std::to_string(m_plate_index + 1));
|
||||
event->status.text = temp + event->status.text;
|
||||
// TRN Slicing progress. %1% is the plate number, %2% the current slicing step.
|
||||
event->status.text = Slic3r::format(_u8L("Slicing plate %1%: %2%"), m_plate_index + 1, event->status.text);
|
||||
}
|
||||
wxQueueEvent(m_plater, event);
|
||||
};
|
||||
|
||||
@@ -676,6 +676,7 @@ void PartSkipDialog::UpdateCountLabel()
|
||||
}
|
||||
m_cnt_label->SetLabel(wxString::Format("%d", check_cnt));
|
||||
m_cnt_label->Fit();
|
||||
// TRN Shown right after the number of selected objects, which is a separate label: "3/10 Selected". %d is the total number of objects.
|
||||
m_tot_label->SetLabel(wxString::Format(_L("/%d Selected"), tot_cnt));
|
||||
m_tot_label->Fit();
|
||||
m_dlg_btn_sizer->Layout();
|
||||
@@ -922,7 +923,8 @@ void PartSkipDialog::OnApplyDialog(wxCommandEvent &event)
|
||||
confirm_dialog.SetMsgLabel(_L("Skipping all objects."));
|
||||
confirm_dialog.SetTipLabel(_L("The printing job will be stopped. Continue?"));
|
||||
} else {
|
||||
confirm_dialog.SetMsgLabel(wxString::Format(_L("Skipping %d objects."), m_partskip_ids.size()));
|
||||
const int skip_cnt = int(m_partskip_ids.size());
|
||||
confirm_dialog.SetMsgLabel(wxString::Format(_L_PLURAL("Skipping %d object.", "Skipping %d objects.", skip_cnt), skip_cnt));
|
||||
confirm_dialog.SetTipLabel(_L("This action cannot be undone. Continue?"));
|
||||
}
|
||||
|
||||
|
||||
+23
-26
@@ -1686,7 +1686,7 @@ ExtruderGroup::NozzleRow ExtruderGroup::create_nozzle_row()
|
||||
plater->update_machine_sync_status();
|
||||
}
|
||||
});
|
||||
combo_flow->SetToolTip(_L("Flow"));
|
||||
combo_flow->SetToolTip(_L_CONTEXT("Flow", "Nozzle Flow"));
|
||||
row.flow = combo_flow;
|
||||
use_nozzle_row_font(combo_flow);
|
||||
|
||||
@@ -4125,13 +4125,12 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
||||
std::vector<NozzleType> nozzle_types(cfg_nozzle_type->size());
|
||||
for (size_t idx = 0; idx < cfg_nozzle_type->size(); ++idx)
|
||||
nozzle_types[idx] = NozzleType(cfg_nozzle_type->values[idx]);
|
||||
nozzle_type = _L( // NEEDFIX this part can be replaced with shorter names
|
||||
nozzle_types[0] == ntHardenedSteel ? "Hardened Steel" :
|
||||
nozzle_types[0] == ntStainlessSteel ? "Stainless Steel" :
|
||||
nozzle_types[0] == ntTungstenCarbide ? "Tungsten Carbide" :
|
||||
nozzle_types[0] == ntBrass ? "Brass"
|
||||
: "-" // Undefined
|
||||
);
|
||||
// NEEDFIX this part can be replaced with shorter names
|
||||
nozzle_type = nozzle_types[0] == ntHardenedSteel ? _L("Hardened Steel") :
|
||||
nozzle_types[0] == ntStainlessSteel ? _L("Stainless Steel") :
|
||||
nozzle_types[0] == ntTungstenCarbide ? _L("Tungsten Carbide") :
|
||||
nozzle_types[0] == ntBrass ? _L("Brass")
|
||||
: wxString("-"); // Undefined
|
||||
}
|
||||
p->label_nozzle_type->SetLabel(nozzle_type);
|
||||
p->label_nozzle_type->SetToolTip(nozzle_type == "-" ? "" : nozzle_type);
|
||||
@@ -4965,7 +4964,7 @@ void Sidebar::collect_physical_filament_info(std::vector<std::string>& color_str
|
||||
|
||||
for (size_t i = 0; i < num_physical; ++i) {
|
||||
auto* combo = p->combos_filament[i];
|
||||
names.push_back(combo ? into_u8(combo->GetValue()) : "Filament " + std::to_string(i + 1));
|
||||
names.push_back(into_u8(combo ? combo->GetValue() : wxString::Format(_L("Filament %d"), int(i + 1))));
|
||||
}
|
||||
|
||||
auto& preset_bundle = *wxGetApp().preset_bundle;
|
||||
@@ -5333,7 +5332,7 @@ void Sidebar::remove_all_mixed_filaments()
|
||||
|
||||
// Worth a confirmation: this drops filament slots the model may be painted with, and anything
|
||||
// painted in one falls back to a plain filament.
|
||||
MessageDialog dlg(this, format_wxstr(_L("Remove all %1% mixed filaments?"), count), _L("Mixed Filament"),
|
||||
MessageDialog dlg(this, format_wxstr(_L_PLURAL("Remove %1% mixed filament?", "Remove all %1% mixed filaments?", count), count), _L("Mixed Filament"),
|
||||
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
|
||||
if (dlg.ShowModal() != wxID_YES)
|
||||
return;
|
||||
@@ -12156,7 +12155,7 @@ void Plater::priv::reload_from_disk()
|
||||
}
|
||||
}
|
||||
else {
|
||||
wxString message = _L("Do you want to replace it") + " ?";
|
||||
wxString message = _L("Do you want to replace it?");
|
||||
MessageDialog dlg(q, message, _L("Message"), wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
#if ENABLE_RELOAD_FROM_DISK_REWORK
|
||||
@@ -13065,9 +13064,7 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
||||
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": event_type %1%, percent %2%, text %3%") % evt.GetEventType() % evt.status.percent % evt.status.text;
|
||||
//BBS: add slice project logic
|
||||
std::string title_text = _u8L("Slicing");
|
||||
evt.status.text = title_text + evt.status.text;
|
||||
// The plate's status callback has already prefixed the text with "Slicing plate N:".
|
||||
if (evt.status.percent >= 0) {
|
||||
if (!m_worker.is_idle()) {
|
||||
// Avoid a race condition
|
||||
@@ -13635,8 +13632,8 @@ static std::vector<wxString> collect_imex_warnings(PartPlate* plate)
|
||||
const int secondary_bed_temp = bed_temps->values[secondary_logical];
|
||||
if (secondary_bed_temp > 0 && std::abs(secondary_bed_temp - primary_bed_temp) > 5) {
|
||||
warnings.push_back(wxString::Format(
|
||||
_L("Bed temperature conflict: T%d (%s) sets the bed to %d\u00B0C \u2014 "
|
||||
"T%d (%s) requires %d\u00B0C. The primary tool controls the bed; "
|
||||
_L("Bed temperature conflict: T%d (%s) sets the bed to %d℃ \u2014 "
|
||||
"T%d (%s) requires %d℃. The primary tool controls the bed; "
|
||||
"secondary tools print at whatever temperature it sets."),
|
||||
primary_tool, primary_display_type, primary_bed_temp,
|
||||
tool_idx, secondary_display_type, secondary_bed_temp));
|
||||
@@ -15698,7 +15695,7 @@ bool Plater::priv::run_textured_mesh_import_dialog(Slic3r::Model& loaded_model,
|
||||
name = preset->label(false);
|
||||
}
|
||||
if (name.empty())
|
||||
name = "Filament " + std::to_string(i + 1);
|
||||
name = into_u8(wxString::Format(_L("Filament %d"), int(i + 1)));
|
||||
entry.name = name;
|
||||
|
||||
if (entry.kind == TextureFilamentKind::ExistingMixed) {
|
||||
@@ -16826,7 +16823,7 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
|
||||
if (accels.empty()) {
|
||||
accels.assign({accel});
|
||||
const auto msg{_L("INFO:") + "\n" +
|
||||
_L("No accelerations provided for calibration. Use default acceleration value ") + std::to_string(long(accel)) + _L(u8"mm/s²")};
|
||||
format_wxstr(_L("No accelerations provided for calibration. Use default acceleration value %1%mm/s²"), long(accel))};
|
||||
get_notification_manager()->push_notification(msg.utf8_string());
|
||||
} else {
|
||||
// set max acceleration in case of batch mode to get correct test pattern size
|
||||
@@ -16891,7 +16888,7 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
|
||||
|
||||
speeds.assign({speed});
|
||||
const auto msg{_L("INFO:") + "\n" +
|
||||
_L("No speeds provided for calibration. Use default optimal speed ") + std::to_string(long(speed)) + _L("mm/s")};
|
||||
format_wxstr(_L("No speeds provided for calibration. Use default optimal speed %1%mm/s"), long(speed))};
|
||||
get_notification_manager()->push_notification(msg.utf8_string());
|
||||
} else if (speeds.size() == 1) {
|
||||
// If we have single value provided, set speed using global configuration.
|
||||
@@ -17315,7 +17312,7 @@ void Plater::calib_temp(const Calib_Params& params) {
|
||||
if (printer_config.has("belt_printer") && printer_config.opt_bool("belt_printer") &&
|
||||
! boost::filesystem::exists(belt_temp_tower_asset(params))) {
|
||||
MessageDialog dlg(static_cast<wxWindow *>(wxGetApp().mainframe),
|
||||
format_wxstr(_L("No belt temperature tower is available for the range %1% to %2% °C. "
|
||||
format_wxstr(_L("No belt temperature tower is available for the range %1% to %2%℃. "
|
||||
"Use a range the tower models cover, for example 230 to 190."),
|
||||
(int) lround(params.start), (int) lround(params.end)),
|
||||
_L("Temperature tower"), wxICON_ERROR | wxOK);
|
||||
@@ -18152,7 +18149,7 @@ void Plater::load_gcode(const wxString& filename)
|
||||
p->preview->get_canvas3d()->zoom_to_plate(0);
|
||||
|
||||
if (p->preview->get_canvas3d()->get_gcode_layers_zs().empty()) {
|
||||
MessageDialog(this, _L("The selected file") + ":\n" + filename + "\n" + _L("Does not contain valid G-code."),
|
||||
MessageDialog(this, format_wxstr(_L("The selected file:\n%1%\ndoes not contain valid G-code."), filename),
|
||||
wxString(GCODEVIEWER_APP_NAME) + " - " + _L("An Error has occurred while loading the G-code file."), wxCLOSE | wxICON_WARNING | wxCENTRE).ShowModal();
|
||||
set_project_filename(_L(DEFAULT_PROJECT_NAME));
|
||||
} else {
|
||||
@@ -23880,7 +23877,7 @@ Plater::ImexGhostTooltip Plater::format_imex_ghost_tooltip(int physical_head) co
|
||||
|
||||
const PartPlate* plate = p->partplate_list.get_curr_plate();
|
||||
if (!plate) {
|
||||
t.label = "T" + std::to_string(physical_head) + " -> (no plate)";
|
||||
t.label = Slic3r::format(_u8L("T%1% -> (no plate)"), physical_head);
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -23891,8 +23888,8 @@ Plater::ImexGhostTooltip Plater::format_imex_ghost_tooltip(int physical_head) co
|
||||
// No filament slot resolves to this physical head. Usually means the printer's
|
||||
// extruder count is understated relative to the filament palette (user added a
|
||||
// filament without extending printer_extruder_id in the Machine tab).
|
||||
t.label = "T" + std::to_string(physical_head) + " — no filament routed\n"
|
||||
"Add an extruder in the Machine tab so this head has a filament slot.";
|
||||
// TRN IDEX/IQEX ghost tooltip. %1% is the number of the physical print head.
|
||||
t.label = Slic3r::format(_u8L("T%1% — no filament routed\nAdd an extruder in the Machine tab so this head has a filament slot."), physical_head);
|
||||
return t;
|
||||
}
|
||||
t.filament_slot_1based = logical + 1;
|
||||
@@ -23900,8 +23897,8 @@ Plater::ImexGhostTooltip Plater::format_imex_ghost_tooltip(int physical_head) co
|
||||
// from one resolution, not two.
|
||||
t.swatch = plate->get_imex_head_filament_color(physical_head, pem, map);
|
||||
t.swatch.a(1.0f); // tooltip swatch opaque
|
||||
t.label = "T" + std::to_string(physical_head) +
|
||||
" -> filament " + std::to_string(t.filament_slot_1based);
|
||||
// TRN IDEX/IQEX ghost tooltip. %1% is the number of the physical print head, %2% the filament it prints.
|
||||
t.label = Slic3r::format(_u8L("T%1% -> filament %2%"), physical_head, t.filament_slot_1based);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@ PluginDialogItem build_plugin_dialog_item(const PluginDescriptor& descriptor)
|
||||
item.display_name = descriptor.name;
|
||||
item.description = !descriptor.is_metadata_valid() && descriptor.has_error() ?
|
||||
descriptor.normalized_error() :
|
||||
(descriptor.description.empty() ? "No description." : descriptor.description);
|
||||
(descriptor.description.empty() ? _u8L("No description.") : descriptor.description);
|
||||
item.author = descriptor.author;
|
||||
item.version = descriptor.version;
|
||||
// The cloud merge overwrites `version` with the latest cloud version, so prefer the preserved local
|
||||
@@ -639,9 +639,9 @@ nlohmann::json PluginsDialog::localized_strings() const
|
||||
{"no_plugins", _u8L("No plugins found")},
|
||||
{"no_match", _u8L("No plugins match \"%s\"")},
|
||||
{"source_mine", _u8L("Mine")},
|
||||
{"source_subscribed", _u8L("Subscribed")},
|
||||
{"source_subscribed", _u8L_CONTEXT("Subscribed", "Plugin")},
|
||||
{"source_orphaned", _u8L("Orphaned")},
|
||||
{"source_local", _u8L("Local")},
|
||||
{"source_local", _u8L_CONTEXT("Local", "Plugin")},
|
||||
{"mixed_capabilities", _u8L("Some plugin capabilities are enabled")},
|
||||
{"collapse_named", _u8L("Collapse %s capabilities")},
|
||||
{"expand_named", _u8L("Expand %s capabilities")},
|
||||
@@ -1094,7 +1094,7 @@ bool PluginsDialog::install_cloud_plugin(const std::string& plugin_key, const st
|
||||
} catch (const std::exception& ex) {
|
||||
error = ex.what();
|
||||
} catch (...) {
|
||||
error = "Unknown error";
|
||||
error = _u8L("Unknown error");
|
||||
}
|
||||
|
||||
if (!downloaded) {
|
||||
@@ -1225,7 +1225,7 @@ void PluginsDialog::update_plugin(const std::string& plugin_key)
|
||||
} catch (const std::exception& ex) {
|
||||
error = ex.what();
|
||||
} catch (...) {
|
||||
error = "Unknown error";
|
||||
error = _u8L("Unknown error");
|
||||
}
|
||||
|
||||
if (!updated) {
|
||||
|
||||
@@ -587,7 +587,7 @@ wxBoxSizer *PreferencesDialog::create_item_language_combobox(wxString title, wxS
|
||||
wxBoxSizer *PreferencesDialog::create_item_region_combobox(wxString title, wxString tooltip)
|
||||
{
|
||||
|
||||
std::vector<wxString> Regions = {_L("Asia-Pacific"), _L("China"), _L("Europe"), _L("North America"), _L("Others")};
|
||||
std::vector<wxString> Regions = {_L("Asia-Pacific"), _L("China"), _L("Europe"), _L("North America"), _L_CONTEXT("Others", "Region")};
|
||||
std::vector<wxString> local_regions = {"Asia-Pacific", "China", "Europe", "North America", "Others"};
|
||||
|
||||
auto vlist = Regions;
|
||||
@@ -1435,8 +1435,10 @@ wxBoxSizer *PreferencesDialog::create_item_network_plugin_version(wxString title
|
||||
#ifdef WIN32
|
||||
wxBoxSizer* PreferencesDialog::create_item_link_association( wxString url_prefix, wxString website_name)
|
||||
{
|
||||
wxString title = _L("Associate") + (boost::format(" %1%://") % url_prefix.c_str()).str();
|
||||
wxString tooltip = _L("Associate") + " " + url_prefix + ":// " + _L("with OrcaSlicer so that Orca can open models from") + " " + website_name;
|
||||
// TRN %s is a URL scheme, for example "prusaslicer".
|
||||
wxString title = wxString::Format(_L("Associate %s://"), url_prefix);
|
||||
// TRN The first %s is a URL scheme, for example "prusaslicer"; the second is a website name.
|
||||
wxString tooltip = wxString::Format(_L("Associate %s:// with OrcaSlicer so that Orca can open models from %s"), url_prefix, website_name);
|
||||
|
||||
std::wstring registered_bin; // not used, just here to provide a ref to check fn
|
||||
bool reg_to_current_instance = wxGetApp().check_url_association(url_prefix.ToStdWstring(), registered_bin);
|
||||
|
||||
@@ -218,7 +218,7 @@ nlohmann::json PresetBundleDialog::localized_strings() const
|
||||
{"update", _u8L("Update")},
|
||||
{"export_presets", _u8L("Export Presets")},
|
||||
{"close", _u8L("Close")},
|
||||
{"open_folder", _u8L("Open folder in explorer")},
|
||||
{"open_folder", _u8L("Show in folder")},
|
||||
{"delete_bundle", _u8L("Delete bundle")},
|
||||
{"unsubscribe_bundle", _u8L("Unsubscribe bundle")},
|
||||
{"update_available", _u8L("Update available")},
|
||||
|
||||
@@ -817,7 +817,8 @@ void FlashforgePrintHostSendDialog::init()
|
||||
content_sizer->Add(m_flashforge_options_sizer, 0, wxEXPAND);
|
||||
|
||||
if (m_supports_material_station)
|
||||
m_status_text->SetLabel(wxString::Format(_L("Detected %d IFS slots on printer."), static_cast<int>(m_slots.size())));
|
||||
m_status_text->SetLabel(wxString::Format(_L_PLURAL("Detected %d IFS slot on printer.", "Detected %d IFS slots on printer.", m_slots.size()),
|
||||
static_cast<int>(m_slots.size())));
|
||||
else
|
||||
m_status_text->SetLabel(_L("This printer does not report a material station."));
|
||||
|
||||
@@ -949,7 +950,8 @@ void FlashforgePrintHostSendDialog::load_slots()
|
||||
m_use_material_station = m_supports_material_station;
|
||||
|
||||
if (m_supports_material_station)
|
||||
m_status_text->SetLabel(wxString::Format(_L("Detected %d IFS slots on printer."), static_cast<int>(m_slots.size())));
|
||||
m_status_text->SetLabel(wxString::Format(_L_PLURAL("Detected %d IFS slot on printer.", "Detected %d IFS slots on printer.", m_slots.size()),
|
||||
static_cast<int>(m_slots.size())));
|
||||
else
|
||||
m_status_text->SetLabel(_L("This printer does not report a material station."));
|
||||
}
|
||||
|
||||
@@ -1312,9 +1312,9 @@ void PrinterFileSystem::RequestUploadFile()
|
||||
if (result != SUCCESS && result != CONTINUE && result != FILE_EXIST) {
|
||||
std::string error_msg = "";
|
||||
if (result == ERROR_CANCEL) {
|
||||
error_msg = _L("User cancels task.").ToStdString();
|
||||
error_msg = _u8L("User cancels task.");
|
||||
} else if (result == FILE_READ_WRITE_ERR || result == FILE_OPEN_ERR) {
|
||||
error_msg = _L("Failed to read file, please try again.").ToStdString();
|
||||
error_msg = _u8L("Failed to read file, please try again.");
|
||||
}
|
||||
wxLogWarning("PrinterFileSystem::UploadFile error: %d\n", result);
|
||||
SendChangedEvent(EVT_UPLOAD_CHANGED, FF_UPLOADCANCEL, error_msg, result);
|
||||
|
||||
@@ -56,7 +56,7 @@ PurgeModeDialog::PurgeModeDialog(wxWindow *parent, PurgeModeDialogType dialog_ty
|
||||
|
||||
bool is_fast_mode = (m_dialog_type == PurgeModeDialogType::FastMode);
|
||||
|
||||
m_standard_panel = new PurgeModeBtnPanel(options_panel, _L("Standard"), _L("Perform full purging with speed and temperature transition for the best print quality."),
|
||||
m_standard_panel = new PurgeModeBtnPanel(options_panel, _L_CONTEXT("Standard", "Mode"), _L("Perform full purging with speed and temperature transition for the best print quality."),
|
||||
"shield");
|
||||
m_standard_panel->SetMinSize(wxSize(FromDIP(200), FromDIP(150)));
|
||||
m_standard_panel->Select(mode == pvmDefault);
|
||||
|
||||
@@ -25,8 +25,11 @@ namespace Slic3r { namespace GUI {
|
||||
RecenterDialog::RecenterDialog(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style)
|
||||
: DPIDialog(parent, id, _L("Confirm"), pos, size, style)
|
||||
{
|
||||
hint1 = _L("Please home all axes (click ");
|
||||
hint2 = _L(") to locate the toolhead's position. This prevents device moving beyond the printable boundary and causing equipment wear.");
|
||||
// TRN %1% marks where the Home button icon is drawn; keep it in the translation.
|
||||
const wxString hint = _L("Please home all axes (click %1%) to locate the toolhead's position. This prevents device moving beyond the printable boundary and causing equipment wear.");
|
||||
const int icon_pos = hint.Find("%1%");
|
||||
hint1 = icon_pos == wxNOT_FOUND ? hint : hint.Left(icon_pos);
|
||||
hint2 = icon_pos == wxNOT_FOUND ? wxString() : hint.Mid(icon_pos + 3);
|
||||
|
||||
init_bitmap();
|
||||
|
||||
|
||||
@@ -946,7 +946,7 @@ void SelectMachineDialog::init_bind()
|
||||
if (!obj) return;
|
||||
|
||||
if (obj->get_dev_id() == e.GetString()) {
|
||||
m_printer_box->SetPrinterName(wxString::FromUTF8(obj->get_dev_name()) + "(LAN)");
|
||||
m_printer_box->SetPrinterName(wxString::FromUTF8(obj->get_dev_name()) + _L("(LAN)"));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -4358,7 +4358,9 @@ void SelectMachineDialog::update_filament_change_count()
|
||||
m_mapping_sugs_sizer->Show(true);
|
||||
m_change_filament_times_sizer->Show(true);
|
||||
m_txt_change_filament_times->Show(true);
|
||||
m_txt_change_filament_times->SetLabel(wxString::Format(_L("Cost %dg filament and %d changes more than optimal grouping."), saving_weight, hand_changes_count));
|
||||
m_txt_change_filament_times->SetLabel(wxString::Format(_L_PLURAL("Cost %dg filament and %d change more than optimal grouping.",
|
||||
"Cost %dg filament and %d changes more than optimal grouping.", hand_changes_count),
|
||||
saving_weight, hand_changes_count));
|
||||
m_txt_change_filament_times->Wrap(FromDIP(580));
|
||||
m_txt_change_filament_times->Layout();
|
||||
}
|
||||
@@ -7062,7 +7064,7 @@ void PrinterInfoBox::SetPrinters(const std::vector<MachineObject*>& sorted_print
|
||||
{
|
||||
wxString shown_dev_name = wxString::FromUTF8(obj->get_dev_name());
|
||||
if (obj->is_lan_mode_printer()) {
|
||||
shown_dev_name += "(LAN)";
|
||||
shown_dev_name += _L("(LAN)");
|
||||
}
|
||||
|
||||
DropDown::Item drop_item;
|
||||
|
||||
@@ -1187,7 +1187,7 @@ void SendToPrinterDialog::update_user_printer()
|
||||
m_list.push_back(it->second);
|
||||
wxString dev_name_text = from_u8(it->second->get_dev_name());
|
||||
if (it->second->is_lan_mode_printer()) {
|
||||
dev_name_text += "(LAN)";
|
||||
dev_name_text += _L("(LAN)");
|
||||
}
|
||||
machine_list_name.Add(dev_name_text);
|
||||
break;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "ActionRegistry.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "NotificationManager.hpp"
|
||||
@@ -93,6 +94,8 @@ nlohmann::json speed_dial_ui_strings()
|
||||
const std::string alt = GUI::shortkey_alt_prefix();
|
||||
const std::string ctrl = GUI::shortkey_ctrl_prefix();
|
||||
return {
|
||||
// TRN Screen-reader label of a Speed Dial action: the first %s is the action name, the second where it comes from (a menu, tab or settings group). Keep the two %s in this order.
|
||||
{"sd_action_from", _u8L("%s from %s")},
|
||||
{"shortcut_alt", alt},
|
||||
{"shortcut_ctrl", ctrl},
|
||||
|
||||
@@ -155,7 +158,7 @@ SpeedDialWebDialog::SpeedDialWebDialog(wxWindow* parent)
|
||||
if (!create_webview("web/dialog/SpeedDial/index.html", wxEmptyString, wxSize(kPopupWidth, kPopupMaxHeight),
|
||||
wxSize(kPopupWidth, kPopupMinHeight))) {
|
||||
auto* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(new wxStaticText(this, wxID_ANY, wxS("wxWebView unavailable")), wxSizerFlags().Border(wxALL, 20));
|
||||
sizer->Add(new wxStaticText(this, wxID_ANY, _L("Web view is unavailable.")), wxSizerFlags().Border(wxALL, 20));
|
||||
SetSizer(sizer);
|
||||
SetClientSize(FromDIP(wxSize(kPopupWidth, kPopupMinHeight)));
|
||||
}
|
||||
|
||||
@@ -698,7 +698,7 @@ void PrintingTaskPanel::create_panel(wxWindow* parent)
|
||||
m_button_pause_resume = new ScalableButton(progress_lr_panel, wxID_ANY, "print_control_pause", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER,true);
|
||||
|
||||
m_button_pause_resume->Bind(wxEVT_ENTER_WINDOW, [this](auto &e) {
|
||||
if (m_button_pause_resume->GetToolTipText() == _L("Pause")) {
|
||||
if (m_button_pause_resume->GetToolTipText() == _L_CONTEXT("Pause", "Verb")) {
|
||||
m_button_pause_resume->SetBitmap_("print_control_pause_hover");
|
||||
}
|
||||
|
||||
@@ -709,7 +709,7 @@ void PrintingTaskPanel::create_panel(wxWindow* parent)
|
||||
|
||||
m_button_pause_resume->Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) {
|
||||
auto buf = m_button_pause_resume->GetClientData();
|
||||
if (m_button_pause_resume->GetToolTipText() == _L("Pause")) {
|
||||
if (m_button_pause_resume->GetToolTipText() == _L_CONTEXT("Pause", "Verb")) {
|
||||
m_button_pause_resume->SetBitmap_("print_control_pause");
|
||||
}
|
||||
|
||||
@@ -1163,7 +1163,7 @@ void PrintingTaskPanel::enable_pause_resume_button(bool enable, std::string type
|
||||
}
|
||||
else if (type == "pause") {
|
||||
m_button_pause_resume->SetBitmap_("print_control_pause");
|
||||
if (m_button_pause_resume->GetToolTipText() != _L("Pause")) { m_button_pause_resume->SetToolTip(_L("Pause")); }
|
||||
if (m_button_pause_resume->GetToolTipText() != _L_CONTEXT("Pause", "Verb")) { m_button_pause_resume->SetToolTip(_L_CONTEXT("Pause", "Verb")); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1518,7 +1518,7 @@ wxBoxSizer *StatusBasePanel::create_monitoring_page()
|
||||
wxBoxSizer *bSizer_monitoring_title;
|
||||
bSizer_monitoring_title = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_staticText_monitoring = new Label(m_panel_monitoring_title, _L("Camera"));
|
||||
m_staticText_monitoring = new Label(m_panel_monitoring_title, _L_CONTEXT("Camera", "Printer camera"));
|
||||
m_staticText_monitoring->Wrap(-1);
|
||||
//m_staticText_monitoring->SetFont(PAGE_TITLE_FONT);
|
||||
m_staticText_monitoring->SetForegroundColour(PAGE_TITLE_FONT_COL);
|
||||
@@ -3876,7 +3876,9 @@ void StatusPanel::update_subtask(MachineObject *obj)
|
||||
if (obj->queue_number <= 0) {
|
||||
prepare_text = wxString::Format(_L("Cloud Slicing..."));
|
||||
} else {
|
||||
prepare_text = wxString::Format(_L("In Cloud Slicing Queue, there are %s tasks ahead of you."), std::to_string(obj->queue_number));
|
||||
prepare_text = wxString::Format(_L_PLURAL("In Cloud Slicing Queue, there is %d task ahead of you.",
|
||||
"In Cloud Slicing Queue, there are %d tasks ahead of you.", obj->queue_number),
|
||||
obj->queue_number);
|
||||
show_percent = false;
|
||||
}
|
||||
} else
|
||||
@@ -4954,7 +4956,7 @@ void StatusPanel::on_switch_speed(wxCommandEvent &event)
|
||||
popUp->SetSize(em * 36, em * 8);
|
||||
step->SetHint(_L("This only takes effect during printing"));
|
||||
step->AppendItem(_L("Silent"), "");
|
||||
step->AppendItem(_L("Standard"), "");
|
||||
step->AppendItem(_L_CONTEXT("Standard", "Mode"), "");
|
||||
step->AppendItem(_L("Sport"), "");
|
||||
step->AppendItem(_L("Ludicrous"), "");
|
||||
|
||||
@@ -6063,22 +6065,26 @@ wxBoxSizer *ScoreDialog::get_button_sizer()
|
||||
<< "] http_error [" << http_error << "] config [" << config << "] image_path [" << need_upload.second << "]";
|
||||
break;
|
||||
case -1:
|
||||
error_info += need_upload.second + _L(" upload failed").ToUTF8().data() + "\n\thttp code:" + std::to_string(http_code) + "\n\thttp_error:" + http_error + "\n";
|
||||
// TRN %s is the path of an image file.
|
||||
error_info += wxString::Format(_L("%s upload failed"), need_upload.second) + "\n\thttp code:" + std::to_string(http_code) + "\n\thttp_error:" + http_error + "\n";
|
||||
m_upload_status_code = StatusCode::UPLOAD_IMG_FAILED;
|
||||
++it;
|
||||
break;
|
||||
case BAMBU_NETWORK_ERR_PARSE_CONFIG_FAILED:
|
||||
error_info += need_upload.second + _L(" upload config prase failed\n").ToUTF8().data() + "\n";
|
||||
// TRN %s is the path of an image file.
|
||||
error_info += wxString::Format(_L("%s upload config parse failed"), need_upload.second) + "\n\n";
|
||||
m_upload_status_code = StatusCode::UPLOAD_IMG_FAILED;
|
||||
++it;
|
||||
break;
|
||||
case BAMBU_NETWORK_ERR_NO_CORRESPONDING_BUCKET:
|
||||
error_info += need_upload.second + _L(" No corresponding storage bucket\n").ToUTF8().data() + "\n";
|
||||
// TRN %s is the path of an image file.
|
||||
error_info += wxString::Format(_L("%s: No corresponding storage bucket"), need_upload.second) + "\n\n";
|
||||
m_upload_status_code = StatusCode::UPLOAD_IMG_FAILED;
|
||||
++it;
|
||||
break;
|
||||
case BAMBU_NETWORK_ERR_OPEN_FILE_FAILED:
|
||||
error_info += need_upload.second + _L(" cannot be opened\n").ToUTF8().data() + "\n";
|
||||
// TRN %s is the path of an image file.
|
||||
error_info += wxString::Format(_L("%s cannot be opened"), need_upload.second) + "\n\n";
|
||||
m_upload_status_code = StatusCode::UPLOAD_IMG_FAILED;
|
||||
++it;
|
||||
break;
|
||||
@@ -6118,9 +6124,8 @@ wxBoxSizer *ScoreDialog::get_button_sizer()
|
||||
if (!error_info.empty()) { BOOST_LOG_TRIVIAL(info) << error_info; }
|
||||
|
||||
dlg_info = new MessageDialog(this,
|
||||
_L("Your comment result cannot be uploaded due to the following reasons:\n\n error code: ") +
|
||||
std::to_string(http_code) + "\n " + _L("error message: ") + http_error +
|
||||
_L("\n\nWould you like to redirect to the webpage to give a rating?"),
|
||||
wxString::Format(_L("Your comment result cannot be uploaded due to the following reasons:\n\n error code: %d\n error message: %s\n\nWould you like to redirect to the webpage to give a rating?"),
|
||||
int(http_code), wxString::FromUTF8(http_error)),
|
||||
wxString(_L("info")), wxOK | wxNO | wxCENTER);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": upload rating picture failed and http error" << http_error;
|
||||
if (dlg_info->ShowModal() == wxID_OK) {
|
||||
|
||||
@@ -2212,7 +2212,7 @@ void SyncAmsInfoDialog::update_user_printer()
|
||||
{
|
||||
m_list.push_back(it->second);
|
||||
wxString dev_name_text = from_u8(it->second->get_dev_name());
|
||||
if (it->second->is_lan_mode_printer()) { dev_name_text += "(LAN)"; }
|
||||
if (it->second->is_lan_mode_printer()) { dev_name_text += _L("(LAN)"); }
|
||||
machine_list_name.Add(dev_name_text);
|
||||
break;
|
||||
}
|
||||
|
||||
+29
-27
@@ -28,6 +28,7 @@
|
||||
#include <set>
|
||||
#include <initializer_list>
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <wx/anybutton.h>
|
||||
@@ -584,7 +585,7 @@ void Tab::create_preset_tab()
|
||||
|
||||
ScalableButton* icon = nullptr;
|
||||
add_scaled_button(panel, &icon, "multi_extruder");
|
||||
icon->SetToolTip(_L("Parameters with this icon can be configurable per nozzle."));
|
||||
icon->SetToolTip(_L("Parameters with this icon can be configured per nozzle."));
|
||||
|
||||
auto sync_box_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sync_box_sizer->Add(m_extruder_sync, 1, wxEXPAND);
|
||||
@@ -620,7 +621,7 @@ void Tab::create_preset_tab()
|
||||
|
||||
ScalableButton* icon = nullptr;
|
||||
add_scaled_button(panel, &icon, "multi_extruder");
|
||||
icon->SetToolTip(_L("Parameters with this icon can be configurable per nozzle."));
|
||||
icon->SetToolTip(_L("Parameters with this icon can be configured per nozzle."));
|
||||
|
||||
wxBoxSizer *top_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL);
|
||||
@@ -4154,7 +4155,8 @@ bool Tab::validate_custom_gcode(const wxString& title, const std::string& gcode)
|
||||
tags.size()),
|
||||
lines);
|
||||
//wxMessageDialog dialog(wxGetApp().mainframe, reports, _L("Found reserved keywords in") + " " + _(title), wxICON_WARNING | wxOK);
|
||||
MessageDialog dialog(wxGetApp().mainframe, reports, _L("Reserved keywords found") + " " + _(title), wxICON_WARNING | wxOK);
|
||||
// TRN %1% is the name of the custom G-code setting, e.g. "Machine start G-code".
|
||||
MessageDialog dialog(wxGetApp().mainframe, reports, format_wxstr(_L("Reserved keywords found in %1%"), _(title)), wxICON_WARNING | wxOK);
|
||||
dialog.ShowModal();
|
||||
}
|
||||
return !invalid;
|
||||
@@ -8091,9 +8093,6 @@ void Tab::delete_preset()
|
||||
auto current_preset = m_presets->get_selected_preset();
|
||||
// Don't let the user delete the ' - default - ' configuration.
|
||||
//BBS: add project embedded preset logic and refine is_external
|
||||
std::string action = _utf8(L("Delete"));
|
||||
//std::string action = current_preset.is_external ? _utf8(L("remove")) : _utf8(L("delete"));
|
||||
// TRN remove/delete
|
||||
wxString msg;
|
||||
bool confirm_delete_third_party_printer = false;
|
||||
bool is_base_preset = false;
|
||||
@@ -8112,8 +8111,10 @@ void Tab::delete_preset()
|
||||
|
||||
DeleteConfirmDialog
|
||||
dlg(parent(), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Delete"),
|
||||
wxString::Format(_L("%d Filament Preset and %d Process Preset is attached to this printer. Those presets would be deleted if the printer is deleted."),
|
||||
filament_preset_num, process_preset_num));
|
||||
// TRN %1% is "N filament preset(s)", %2% is "N process preset(s)".
|
||||
format_wxstr(_L("%1% and %2% are attached to this printer. Those presets would be deleted if the printer is deleted."),
|
||||
wxString::Format(_L_PLURAL("%d filament preset", "%d filament presets", filament_preset_num), filament_preset_num),
|
||||
wxString::Format(_L_PLURAL("%d process preset", "%d process presets", process_preset_num), process_preset_num)));
|
||||
int res = dlg.ShowModal();
|
||||
if (res != wxID_OK) return;
|
||||
confirm_delete_third_party_printer = true;
|
||||
@@ -8128,9 +8129,9 @@ void Tab::delete_preset()
|
||||
if (count > 0) {
|
||||
msg = _L("Presets inherited by other presets cannot be deleted!");
|
||||
msg += "\n";
|
||||
msg += _L_PLURAL("The following presets inherit this preset.",
|
||||
"The following preset inherits this preset.", count);
|
||||
wxString title = from_u8((boost::format(_utf8(L("%1% Preset"))) % action).str()); // action + _(L(" Preset"));
|
||||
msg += _L_PLURAL("The following preset inherits this preset.",
|
||||
"The following presets inherit this preset.", count);
|
||||
wxString title = _L("Delete Preset");
|
||||
MessageDialog(parent(), msg + presets, title, wxOK | wxICON_ERROR).ShowModal();
|
||||
return;
|
||||
}
|
||||
@@ -8177,17 +8178,13 @@ void Tab::delete_preset()
|
||||
}
|
||||
}
|
||||
|
||||
if (is_base_preset && (current_preset.type == Preset::Type::TYPE_FILAMENT) && action == _utf8(L("Delete"))) {
|
||||
if (is_base_preset && (current_preset.type == Preset::Type::TYPE_FILAMENT)) {
|
||||
msg += from_u8(_u8L("Are you sure to delete the selected preset?\nIf the preset corresponds to a filament currently in use on your printer, please reset the filament information for that slot."));
|
||||
} else {
|
||||
msg += from_u8((boost::format(_u8L("Are you sure you want to %1% the selected preset\?")) % action).str());
|
||||
msg += _L("Are you sure you want to delete the selected preset?");
|
||||
}
|
||||
|
||||
//BBS: add project embedded preset logic and refine is_external
|
||||
action = _utf8(L("Delete"));
|
||||
//action = current_preset.is_external ? _utf8(L("Remove")) : _utf8(L("Delete"));
|
||||
// TRN Remove/Delete
|
||||
wxString title = from_u8((boost::format(_utf8(L("%1% Preset"))) % action).str()); //action + _(L(" Preset"));
|
||||
wxString title = _L("Delete Preset");
|
||||
if (current_preset.is_default || !(confirm_delete_third_party_printer ||
|
||||
//wxID_YES != wxMessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal())
|
||||
wxID_YES == MessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal()))
|
||||
@@ -8743,15 +8740,20 @@ static wxString short_nozzle_volume_name(const std::string &volume_name)
|
||||
// Hybrid has no entry on purpose: it is never a variant string, and the switch lists its two
|
||||
// sub-nozzle types as separate tags (see generate_extruder_options).
|
||||
if (volume_name == "Standard")
|
||||
return "SF";
|
||||
// TRN Short tag for the Standard nozzle flow type.
|
||||
return _L_CONTEXT("SF", "Nozzle flow type");
|
||||
if (volume_name == "High Flow")
|
||||
return "HF";
|
||||
// TRN Short tag for the High Flow nozzle flow type.
|
||||
return _L_CONTEXT("HF", "Nozzle flow type");
|
||||
if (volume_name == "TPU High Flow")
|
||||
return "TPU HF";
|
||||
// TRN Short tag for the TPU High Flow nozzle flow type.
|
||||
return _L_CONTEXT("TPU HF", "Nozzle flow type");
|
||||
if (volume_name == "E3D High Flow")
|
||||
return "E3D HF";
|
||||
// TRN Short tag for the E3D High Flow nozzle flow type.
|
||||
return _L_CONTEXT("E3D HF", "Nozzle flow type");
|
||||
if (volume_name == "Extra High Flow")
|
||||
return "XHF";
|
||||
// TRN Short tag for the Extra High Flow nozzle flow type.
|
||||
return _L_CONTEXT("XHF", "Nozzle flow type");
|
||||
return from_u8(volume_name);
|
||||
}
|
||||
|
||||
@@ -8795,7 +8797,7 @@ std::vector<wxString> Tab::generate_extruder_options()
|
||||
nozzle = "";
|
||||
}
|
||||
}
|
||||
options.push_back(wxString::Format(_L("%s %s"), _L(drive), short_nozzle_volume_name(nozzle)));
|
||||
options.push_back(wxString::Format("%s %s", _L(drive), short_nozzle_volume_name(nozzle)));
|
||||
}
|
||||
return options;
|
||||
}
|
||||
@@ -8829,10 +8831,10 @@ std::vector<wxString> Tab::generate_extruder_options()
|
||||
NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volumes->values[i]);
|
||||
|
||||
if (volume_type == NozzleVolumeType::nvtHybrid) {
|
||||
options.push_back(wxString::Format(_L("%s %s"), extruder_name, short_nozzle_volume_name(get_nozzle_volume_type_string(NozzleVolumeType::nvtStandard))));
|
||||
options.push_back(wxString::Format(_L("%s %s"), extruder_name, short_nozzle_volume_name(get_nozzle_volume_type_string(NozzleVolumeType::nvtHighFlow))));
|
||||
options.push_back(wxString::Format("%s %s", extruder_name, short_nozzle_volume_name(get_nozzle_volume_type_string(NozzleVolumeType::nvtStandard))));
|
||||
options.push_back(wxString::Format("%s %s", extruder_name, short_nozzle_volume_name(get_nozzle_volume_type_string(NozzleVolumeType::nvtHighFlow))));
|
||||
} else {
|
||||
options.push_back(wxString::Format(_L("%s %s"), extruder_name,
|
||||
options.push_back(wxString::Format("%s %s", extruder_name,
|
||||
short_nozzle_volume_name(get_nozzle_volume_type_string(volume_type))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,7 +633,9 @@ public:
|
||||
decompose_label->SetCursor(wxCursor(add_enabled ? wxCURSOR_HAND : wxCURSOR_ARROW));
|
||||
if (!add_enabled)
|
||||
add_label->SetToolTip(wxString::Format(
|
||||
_L("The project supports up to %d filaments. Extra filaments will be discarded."),
|
||||
_L_PLURAL("The project supports up to %d filament. Extra filaments will be discarded.",
|
||||
"The project supports up to %d filaments. Extra filaments will be discarded.",
|
||||
(int)EnforcerBlockerType::ExtruderMax),
|
||||
(int)EnforcerBlockerType::ExtruderMax));
|
||||
decompose_label->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent&) {
|
||||
if (m_can_add_filament && !m_can_add_filament())
|
||||
@@ -2324,7 +2326,9 @@ void TextureImportDialog::build_bottom_buttons(wxSizer* sizer)
|
||||
{
|
||||
m_drop_warning_label = new wxStaticText(this, wxID_ANY,
|
||||
wxString::Format(
|
||||
_L("The project supports up to %d filaments. Extra filaments will be discarded."),
|
||||
_L_PLURAL("The project supports up to %d filament. Extra filaments will be discarded.",
|
||||
"The project supports up to %d filaments. Extra filaments will be discarded.",
|
||||
(int)max_filament_count()),
|
||||
(int)max_filament_count()));
|
||||
m_drop_warning_label->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#FF6F00")));
|
||||
m_drop_warning_label->SetFont(texture_import_section_title_font(this));
|
||||
|
||||
@@ -1184,7 +1184,8 @@ void TroubleshootDialog::UpdateLogsStorage()
|
||||
}
|
||||
|
||||
bool is_mb = total_bytes >= 1024 * 1024;
|
||||
wxString label = total_bytes > 0 ? wxString::Format("%d %s (%.2f %s)", file_count, _L("log(s)"), total_bytes / (1024.0 * (is_mb ? 1024.0 : 1.0)), is_mb ? "MB" : "KB") : "";
|
||||
// TRN Number of log files, then their total size and its unit (KB or MB).
|
||||
wxString label = total_bytes > 0 ? wxString::Format(_L_PLURAL("%d log (%.2f %s)", "%d logs (%.2f %s)", file_count), file_count, total_bytes / (1024.0 * (is_mb ? 1024.0 : 1.0)), is_mb ? "MB" : "KB") : "";
|
||||
m_logs_storage->SetLabel(label);
|
||||
}
|
||||
|
||||
|
||||
@@ -382,16 +382,22 @@ void UVEditorCanvas::update_status()
|
||||
_L("Pick Unwrap as a texture layer's mapping to edit its UVs here");
|
||||
else if (m_select_mode == SelectMode::Vertex)
|
||||
msg = m_sel_vertices.size() > 1 ?
|
||||
wxString::Format(_L("%d vertices selected | drag = move together, Shift/Ctrl click = add/remove"),
|
||||
wxString::Format(_L_PLURAL("%d vertex selected | drag = move together, Shift/Ctrl click = add/remove",
|
||||
"%d vertices selected | drag = move together, Shift/Ctrl click = add/remove",
|
||||
m_sel_vertices.size()),
|
||||
int(m_sel_vertices.size())) :
|
||||
_L("Vertex mode: drag a vertex to reshape | Shift/Ctrl click = multi-select, wheel = zoom, Home = frame");
|
||||
else if (m_select_mode == SelectMode::Edge)
|
||||
msg = m_sel_edges.size() > 1 ?
|
||||
wxString::Format(_L("%d edges selected | drag = move together, Shift/Ctrl click = add/remove"),
|
||||
wxString::Format(_L_PLURAL("%d edge selected | drag = move together, Shift/Ctrl click = add/remove",
|
||||
"%d edges selected | drag = move together, Shift/Ctrl click = add/remove",
|
||||
m_sel_edges.size()),
|
||||
int(m_sel_edges.size())) :
|
||||
_L("Edge mode: drag an island edge to reshape | Shift/Ctrl click = multi-select, wheel = zoom, Home = frame");
|
||||
else if (m_selection.size() > 1)
|
||||
msg = wxString::Format(_L("%d islands selected | drag = move together, Shift/Ctrl click = add/remove, R/S = rotate/scale primary"),
|
||||
msg = wxString::Format(_L_PLURAL("%d island selected | drag = move together, Shift/Ctrl click = add/remove, R/S = rotate/scale primary",
|
||||
"%d islands selected | drag = move together, Shift/Ctrl click = add/remove, R/S = rotate/scale primary",
|
||||
m_selection.size()),
|
||||
int(m_selection.size()));
|
||||
else if (m_selected_island >= 0)
|
||||
msg = wxString::Format(_L("Island %d selected | drag = move, R = rotate, S = scale, Shift/Ctrl click = multi-select, Home = frame"),
|
||||
@@ -2010,8 +2016,8 @@ UVEditorPanel::UVEditorPanel(wxWindow *parent) : wxPanel(parent, wxID_ANY)
|
||||
m_layer_name->SetMinSize(wxSize(FromDIP(30), -1));
|
||||
m_tile = text(wxEmptyString, c.dim);
|
||||
m_tile->SetToolTip(_L("The active layer's tile size: how much of the model one repeat of the texture covers. The "
|
||||
"canvas is measured in tiles, so one grid cell is one repeat. Change it with Tiling in the "
|
||||
"layer's settings."));
|
||||
"canvas is measured in tiles, so one grid cell is one repeat. Change it with Tile size in "
|
||||
"the layer's settings."));
|
||||
header->Add(m_thumb, 0, wxALIGN_CENTER_VERTICAL);
|
||||
header->Add(m_layer_name, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, gap);
|
||||
header->Add(m_tile, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, gap);
|
||||
@@ -2229,8 +2235,9 @@ void UVEditorPanel::apply_state(const UVEditorCanvas::PaneState &s)
|
||||
_L("No islands have been reshaped by hand, so there is nothing to "
|
||||
"discard."));
|
||||
|
||||
m_stats->SetLabel(s.unwrapped ? wxString::Format(_L("%d islands, %s faces"), s.island_count,
|
||||
wxString(std::to_string(s.face_count))) :
|
||||
m_stats->SetLabel(s.unwrapped ? wxString::Format(_L_PLURAL("%d island", "%d islands", s.island_count), s.island_count) + ", " +
|
||||
wxString::Format(_L_PLURAL("%s face", "%s faces", s.face_count),
|
||||
wxString(std::to_string(s.face_count))) :
|
||||
wxString());
|
||||
m_stats->SetToolTip(s.unwrapped ? _L("How the painted area came out of the unwrap: the number of separate pieces it "
|
||||
"was cut into (at the seams and at edges sharper than the seam angle), and how "
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoBase.hpp"
|
||||
#include <memory>
|
||||
#include "slic3r/GUI/GUI_Utils.hpp"
|
||||
@@ -2165,7 +2166,8 @@ void DiffPresetDialog::update_tree()
|
||||
|
||||
preset_combos.equal_bmp->SetToolTip(wxEmptyString);
|
||||
|
||||
m_tree->model->AddPreset(type, "\"" + from_u8(left_preset->name) + "\" vs \"" + from_u8(right_preset->name) + "\"", left_pt);
|
||||
// TRN Header of a preset comparison: the two preset names.
|
||||
m_tree->model->AddPreset(type, format_wxstr(_L("\"%1%\" vs \"%2%\""), left_preset->name, right_preset->name), left_pt);
|
||||
|
||||
const std::map<wxString, std::string>& category_icon_map = wxGetApp().get_tab(type)->get_category_icon_map();
|
||||
auto get_category_icon = [&category_icon_map](const wxString& key) {
|
||||
|
||||
@@ -92,6 +92,8 @@ static json guide_strings()
|
||||
{
|
||||
return {
|
||||
{"loading", _u8L("Loading…")},
|
||||
// TRN Sidebar entry of the printer selection page for the group of custom (user-defined) printers.
|
||||
{"custom_vendor", _u8L_CONTEXT("Custom", "Printer vendor")},
|
||||
{"welcome", _u8L("Welcome to Orca Slicer")},
|
||||
{"setup_intro", _u8L("Orca Slicer will be set up in several steps. Let's start!")},
|
||||
{"get_started", _u8L("Get Started")},
|
||||
@@ -100,7 +102,7 @@ static json guide_strings()
|
||||
{"china", _u8L("China")},
|
||||
{"europe", _u8L("Europe")},
|
||||
{"north_america", _u8L("North America")},
|
||||
{"others", _u8L("Others")},
|
||||
{"others", _u8L_CONTEXT("Others", "Region")},
|
||||
{"back", _u8L_CONTEXT("Back", "Navigation")},
|
||||
{"next", _u8L("Next")},
|
||||
{"finish", _u8L("Finish")},
|
||||
|
||||
@@ -60,6 +60,8 @@ static json home_page_strings()
|
||||
{
|
||||
return {
|
||||
{"login", _u8L("Login")},
|
||||
// TRN Short badge on a recent project that was published (a published 3MF). Keep it about three letters long.
|
||||
{"published_badge", _u8L("PUB")},
|
||||
{"not_signed_in", _u8L("Not signed in")},
|
||||
{"plugin_not_detected", _u8L("Bambu Network plug-in not detected. Click <a>here</a> to install it.")},
|
||||
{"log_out", _u8L("Log Out")},
|
||||
|
||||
@@ -802,7 +802,7 @@ void FanControlPopupNew::UpdatePartSubMode()
|
||||
// Submode for cooling filter
|
||||
if (AIR_DUCT(m_data.curren_mode) == AIR_DUCT::AIR_DUCT_COOLING_FILT && m_data.IsSupportCoolingFilter()) {
|
||||
if (!m_cooling_filter_switch_panel) {
|
||||
m_cooling_filter_switch_panel = new FanControlNewSwitchPanel(m_sub_mode_panel, _L("Filter"), _L("Enabling filtration redirects the right fan to filter gas, which may reduce cooling performance."));
|
||||
m_cooling_filter_switch_panel = new FanControlNewSwitchPanel(m_sub_mode_panel, _L_CONTEXT("Filter", "air_duct"), _L("Enabling filtration redirects the right fan to filter gas, which may reduce cooling performance."));
|
||||
m_cooling_filter_switch_panel->Bind(EVT_FANCTRL_SWITCH, [this] (wxCommandEvent& evt)
|
||||
{
|
||||
if (m_obj && m_obj->is_in_printing()) {
|
||||
|
||||
@@ -53,15 +53,17 @@ FilamentLoad::FilamentLoad(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
||||
// STEP_CHECK_POSITION and STEP_CONFIRM_EXTRUDED share code 0x08, so CONFIRM is assigned first
|
||||
// and CHECK_POSITION last, leaving code 0x08 mapped to "Check filament location" as on device.
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_IDLE] = _L("Idling...");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PAUSE] = _L("Pause");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PAUSE] = _L_CONTEXT("Pause", "Verb");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_HEAT_NOZZLE] = _L("Heat the nozzle");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_CUT_FILAMENT] = _L("Cut filament");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PULL_CURR_FILAMENT] = _L("Pull back the current filament");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PUSH_NEW_FILAMENT] = _L("Push new filament into extruder");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_GRAB_NEW_FILAMENT] = _L("Grab new filament");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PURGE_OLD_FILAMENT] = _L("Purge old filament");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_SWITCH_EXTRUDER] = _L("Switch") + " " + _L("extruder");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_SWITCH_HOTEND] = _L("Switch") + " " + _L("hotend");
|
||||
// TRN Filament change step: the printer switches to the other extruder.
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_SWITCH_EXTRUDER] = _L("Switch extruder");
|
||||
// TRN Filament change step: the printer switches to another hotend.
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_SWITCH_HOTEND] = _L("Switch hotend");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_AMS_FILA_COOLING] = _L("Wait for AMS cooling");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PUSH_SWITCHER_FILA] = _L("Switch current filament at Filament Track Switch");
|
||||
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PULL_SWITCHER_FILA] = _L("Pull back current filament at Filament Track Switch");
|
||||
|
||||
@@ -38,8 +38,12 @@
|
||||
#include "Widgets/Label.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "DeviceCore/DevConfigUtil.h"
|
||||
#include "DeviceCore/DevDefs.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "slic3r/GUI/Jobs/SendJob.hpp"
|
||||
#include "slic3r/GUI/Widgets/WebViewHostDialog.hpp"
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
@@ -409,14 +413,18 @@ wxString WipingDialog::BuildTextObjStr(bool multi_language)
|
||||
wxString ok_btn_label;
|
||||
wxString cancel_btn_label;
|
||||
|
||||
const std::string pt = wxGetApp().preset_bundle->printers.get_edited_preset().get_printer_type(wxGetApp().preset_bundle);
|
||||
const std::string extruder_name_0 = DevPrinterConfigUtil::get_toolhead_display_name(pt, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Extruder, ToolHeadNameCase::SentenceCase);
|
||||
const std::string extruder_name_1 = DevPrinterConfigUtil::get_toolhead_display_name(pt, MAIN_EXTRUDER_ID, ToolHeadComponent::Extruder, ToolHeadNameCase::SentenceCase);
|
||||
|
||||
if (multi_language) {
|
||||
auto_flush_tip = _L("Orca would re-calculate your flushing volumes everytime the filaments color changed or filaments changed. You could disable the auto-calculate in Orca Slicer > Preferences");
|
||||
volume_desp_panel = _L("Flushing volume (mm³) for each filament pair.");
|
||||
volume_range_panel = wxString::Format(_L("Suggestion: Flushing Volume in range [%d, %d]"), 0, 700);
|
||||
multiplier_range_panel = wxString::Format(_L("The multiplier should be in range [%.2f, %.2f]."), 0, 3);
|
||||
multiplier_range_panel = wxString::Format(_L("The multiplier should be in range [%.2f, %.2f]."), 0., 3.);
|
||||
calc_btn_panel = _L("Re-calculate");
|
||||
extruder_label_0 = _L("Left extruder");
|
||||
extruder_label_1 = _L("Right extruder");
|
||||
extruder_label_0 = _L(extruder_name_0);
|
||||
extruder_label_1 = _L(extruder_name_1);
|
||||
multiplier_label = _L("Multiplier");
|
||||
ok_btn_label = _L("OK");
|
||||
cancel_btn_label = _L("Cancel");
|
||||
@@ -424,10 +432,10 @@ wxString WipingDialog::BuildTextObjStr(bool multi_language)
|
||||
auto_flush_tip = "Orca would re-calculate your flushing volumes everytime the filaments color changed or filaments changed. You could disable the auto-calculate in Orca Slicer > Preferences";
|
||||
volume_desp_panel = wxString::FromUTF8("Flushing volume (mm³) for each filament pair.");
|
||||
volume_range_panel = wxString::Format("Suggestion: Flushing Volume in range [%d, %d]", 0, 700);
|
||||
multiplier_range_panel = wxString::Format("The multiplier should be in range [%.2f, %.2f].", 0, 3);
|
||||
multiplier_range_panel = wxString::Format("The multiplier should be in range [%.2f, %.2f].", 0., 3.);
|
||||
calc_btn_panel = "Re-calculate";
|
||||
extruder_label_0 = "Left extruder";
|
||||
extruder_label_1 = "Right extruder";
|
||||
extruder_label_0 = wxString::FromUTF8(extruder_name_0);
|
||||
extruder_label_1 = wxString::FromUTF8(extruder_name_1);
|
||||
multiplier_label = "Multiplier";
|
||||
ok_btn_label = "OK";
|
||||
cancel_btn_label = "Cancel";
|
||||
@@ -490,6 +498,12 @@ WipingDialog::WipingDialog(wxWindow* parent, const int max_flush_volume) :
|
||||
wxNO_BORDER);
|
||||
|
||||
m_webview->AddScriptMessageHandler("wipingDialog");
|
||||
// The page's strings (resources/web/flush/WipingDialog.html), keyed by their T() ids.
|
||||
const nlohmann::json page_strings = {
|
||||
// TRN Corner header of the flushing volume table: rows are the filament flushed from, columns the filament changed to.
|
||||
{"from_to", _u8L("from/to")},
|
||||
};
|
||||
m_webview->AddUserScript(wxString::FromUTF8(WebViewHostDialog::localized_strings_script(page_strings)));
|
||||
main_sizer->Add(m_webview, 1, wxEXPAND);
|
||||
|
||||
fs::path filepath = fs::path(resources_dir()) / "web/flush/WipingDialog.html";
|
||||
|
||||
@@ -456,7 +456,7 @@ Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plat
|
||||
// per-show in on_show() rather than gated here at construction time.
|
||||
auto labeled_box_model = new LabeledStaticBox(this, _L("Test model"));
|
||||
m_model_box = new wxStaticBoxSizer(labeled_box_model, wxHORIZONTAL);
|
||||
m_rbModel = new RadioGroup(this, { _L("Standard"), _L("Overhang") }, wxVERTICAL);
|
||||
m_rbModel = new RadioGroup(this, { _L_CONTEXT("Standard", "Test model"), _L_CONTEXT("Overhang", "Test model") }, wxVERTICAL);
|
||||
m_model_box->Add(m_rbModel, 0, wxALL | wxEXPAND, FromDIP(4));
|
||||
v_sizer->Add(m_model_box, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
|
||||
|
||||
@@ -679,7 +679,7 @@ MaxVolumetricSpeed_Test_Dlg::MaxVolumetricSpeed_Test_Dlg(wxWindow* parent, wxWin
|
||||
// Settings
|
||||
wxString start_vol_str = _L("Start volumetric speed: ");
|
||||
wxString end_vol_str = _L("End volumetric speed: ");
|
||||
wxString vol_step_str = _L("Step") + ": ";
|
||||
wxString vol_step_str = _L_CONTEXT("Step", "Increment") + ": ";
|
||||
int text_max = GetTextMax(this, std::vector<wxString>{start_vol_str, end_vol_str, vol_step_str});
|
||||
|
||||
auto st_size = wxSize(text_max, -1);
|
||||
@@ -792,7 +792,7 @@ VFA_Test_Dlg::VFA_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
|
||||
// Settings
|
||||
wxString start_str = _L("Start speed: ");
|
||||
wxString end_vol_str = _L("End speed: ");
|
||||
wxString vol_step_str = _L("Step") + ": ";
|
||||
wxString vol_step_str = _L_CONTEXT("Step", "Increment") + ": ";
|
||||
int text_max = GetTextMax(this, std::vector<wxString>{start_str, end_vol_str, vol_step_str});
|
||||
|
||||
auto st_size = wxSize(text_max, -1);
|
||||
@@ -1054,7 +1054,7 @@ Retraction_Test_Dlg::Retraction_Test_Dlg(wxWindow* parent, wxWindowID id, Plater
|
||||
// Settings
|
||||
wxString start_length_str = _L("Start retraction length: ");
|
||||
wxString end_length_str = _L("End retraction length: ");
|
||||
wxString length_step_str = _L("Step") + ": ";
|
||||
wxString length_step_str = _L_CONTEXT("Step", "Increment") + ": ";
|
||||
int text_max = GetTextMax(this, std::vector<wxString>{start_length_str, end_length_str, length_step_str});
|
||||
|
||||
auto st_size = wxSize(text_max, -1);
|
||||
@@ -1212,8 +1212,8 @@ Input_Shaping_Freq_Test_Dlg::Input_Shaping_Freq_Test_Dlg(wxWindow* parent, wxWin
|
||||
v_sizer->Add(type_box, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
|
||||
|
||||
// Settings
|
||||
wxString x_axis_str = reprap_firmware ? _L("Frequency (Start / End): ") : "X " + _L("Start / End") + ": ";
|
||||
wxString y_axis_str = "Y " + _L("Start / End") + ": ";
|
||||
wxString x_axis_str = reprap_firmware ? _L("Frequency (Start / End): ") : _L("X Start / End: ");
|
||||
wxString y_axis_str = _L("Y Start / End: ");
|
||||
int text_max = GetTextMax(this, std::vector<wxString>{x_axis_str, y_axis_str});
|
||||
|
||||
auto st_size = wxSize(text_max, -1);
|
||||
@@ -1437,8 +1437,8 @@ Input_Shaping_Damp_Test_Dlg::Input_Shaping_Damp_Test_Dlg(wxWindow* parent, wxWin
|
||||
v_sizer->Add(type_box, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
|
||||
|
||||
// Settings
|
||||
wxString freq_str = reprap_firmware ? _L("Frequency: ") : _L("Frequency") + " X / Y: ";
|
||||
wxString damp_str = _L("Damp") + " " + _L("Start / End") + ": ";
|
||||
wxString freq_str = reprap_firmware ? _L("Frequency: ") : _L("Frequency X / Y: ");
|
||||
wxString damp_str = _L("Damp (Start / End): ");
|
||||
int text_max = GetTextMax(this, std::vector<wxString>{freq_str, damp_str});
|
||||
|
||||
auto st_size = wxSize(text_max, -1);
|
||||
|
||||
@@ -238,7 +238,7 @@ private:
|
||||
if (m_cancelled || m_attempt >= m_max_retries) {
|
||||
if (m_attempt >= m_max_retries) {
|
||||
m_resp.put("result", false);
|
||||
m_resp.put("message", "Maximum login retries exceeded");
|
||||
m_resp.put("message", _u8L("Maximum login retries exceeded"));
|
||||
}
|
||||
wxQueueEvent(this, new wxThreadEvent(wxEVT_THREAD, wxID_ABORT));
|
||||
return;
|
||||
@@ -256,7 +256,8 @@ private:
|
||||
http.on_error([this](std::string, std::string error, unsigned status) {
|
||||
if (!m_cancelled) {
|
||||
m_resp.put("result", false);
|
||||
m_resp.put("message", (status != 200) ? "HTTP error: " + std::to_string(status) : error);
|
||||
// TRN %1% is an HTTP status code.
|
||||
m_resp.put("message", (status != 200) ? Slic3r::GUI::format(_u8L("HTTP error: %1%"), status) : error);
|
||||
wxQueueEvent(this, new wxThreadEvent(wxEVT_THREAD, wxID_ABORT));
|
||||
}
|
||||
})
|
||||
@@ -264,7 +265,7 @@ private:
|
||||
if (!m_cancelled) {
|
||||
if (status != 200) {
|
||||
m_resp.put("result", false);
|
||||
m_resp.put("message", "HTTP error: " + std::to_string(status));
|
||||
m_resp.put("message", Slic3r::GUI::format(_u8L("HTTP error: %1%"), status));
|
||||
wxQueueEvent(this, new wxThreadEvent(wxEVT_THREAD, wxID_ABORT));
|
||||
return;
|
||||
}
|
||||
@@ -274,7 +275,7 @@ private:
|
||||
pt::read_json(ss, m_resp);
|
||||
} catch (...) {
|
||||
m_resp.put("result", false);
|
||||
m_resp.put("message", "Could not parse server response");
|
||||
m_resp.put("message", _u8L("Could not parse server response."));
|
||||
}
|
||||
|
||||
if (m_resp.get<bool>("result", false) && m_resp.get_optional<std::string>("message.session").has_value()) {
|
||||
@@ -349,7 +350,7 @@ bool C3DPrinterOS::login(wxString& msg) const
|
||||
session = login_resp.get<std::string>("message.session");
|
||||
email = login_resp.get<std::string>("message.email");
|
||||
} else {
|
||||
msg = wxString(login_resp.get<std::string>("message").c_str());
|
||||
msg = wxString::FromUTF8(login_resp.get<std::string>("message"));
|
||||
return false;
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
@@ -365,7 +366,11 @@ bool C3DPrinterOS::login(wxString& msg) const
|
||||
|
||||
wxString C3DPrinterOS::get_test_ok_msg() const
|
||||
{
|
||||
return _("Connection to 3DPrinterOS cloud works correctly.") + (!m_username.empty() ? "" + _(" Logined as user: ") + m_username : "");
|
||||
wxString msg = _L("Connection to 3DPrinterOS cloud works correctly.");
|
||||
if (!m_username.empty())
|
||||
// TRN %1% is the 3DPrinterOS account (e-mail address).
|
||||
msg += " " + GUI::format_wxstr(_L("Logged in as user: %1%"), m_username);
|
||||
return msg;
|
||||
}
|
||||
|
||||
wxString C3DPrinterOS::get_test_failed_msg(wxString &msg) const
|
||||
@@ -471,7 +476,7 @@ bool C3DPrinterOS::upload(
|
||||
pt::read_json(ss, uploadResponse);
|
||||
} catch (const std::exception &) {
|
||||
uploadResponse.put("result", false);
|
||||
uploadResponse.put("message", "Could not parse server response");
|
||||
uploadResponse.put("message", _u8L("Could not parse server response."));
|
||||
}
|
||||
})
|
||||
.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
@@ -491,7 +496,7 @@ bool C3DPrinterOS::upload(
|
||||
file_id = uploadResponse.get<std::string>("message.file_id");
|
||||
} else {
|
||||
res = false;
|
||||
error_fn(uploadResponse.get<std::string>("message"));
|
||||
error_fn(wxString::FromUTF8(uploadResponse.get<std::string>("message")));
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
res = false;
|
||||
@@ -551,7 +556,7 @@ std::string C3DPrinterOS::get_api_auth_token(wxString &err) const
|
||||
if (resp.get<bool>("result")) {
|
||||
result = resp.get<std::string>("message");
|
||||
} else {
|
||||
err = wxString(resp.get<std::string>("message").c_str());
|
||||
err = wxString::FromUTF8(resp.get<std::string>("message"));
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
err = _L("Could not parse server response.");
|
||||
@@ -573,7 +578,7 @@ bool C3DPrinterOS::check_session(wxString &msg) const {
|
||||
if (resp.get<bool>("result")) {
|
||||
return true;
|
||||
} else {
|
||||
msg = wxString(resp.get<std::string>("message").c_str());
|
||||
msg = wxString::FromUTF8(resp.get<std::string>("message"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -646,7 +651,7 @@ void C3DPrinterOS::send_form(
|
||||
pt::read_json(ss, responseTree);
|
||||
} catch (const std::exception &) {
|
||||
responseTree.put("result", false);
|
||||
responseTree.put("message", "Could not parse server response");
|
||||
responseTree.put("message", _u8L("Could not parse server response."));
|
||||
}
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <utility>
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "slic3r/Utils/FileTransferUtils.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <cwchar>
|
||||
@@ -97,7 +98,7 @@ int BBLNetworkPlugin::initialize(bool using_backup, const std::string& version)
|
||||
if (version.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": version is required but not provided";
|
||||
set_load_error(
|
||||
"Network library version not specified",
|
||||
_u8L("Network library version not specified"),
|
||||
"A version must be specified to load the network library",
|
||||
""
|
||||
);
|
||||
@@ -150,7 +151,7 @@ int BBLNetworkPlugin::initialize(bool using_backup, const std::string& version)
|
||||
std::string library_path = get_libpath_in_current_directory(std::string(BAMBU_NETWORK_LIBRARY));
|
||||
if (library_path.empty()) {
|
||||
set_load_error(
|
||||
"Network library not found",
|
||||
_u8L("Network library not found"),
|
||||
"Could not locate versioned library: " + library,
|
||||
library
|
||||
);
|
||||
@@ -166,7 +167,7 @@ int BBLNetworkPlugin::initialize(bool using_backup, const std::string& version)
|
||||
char* dll_error = dlerror();
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": dlopen failed: " << (dll_error ? dll_error : "unknown error");
|
||||
set_load_error(
|
||||
"Failed to load network library",
|
||||
_u8L("Failed to load network library"),
|
||||
dll_error ? std::string(dll_error) : "Unknown dlopen error",
|
||||
library
|
||||
);
|
||||
@@ -176,7 +177,7 @@ int BBLNetworkPlugin::initialize(bool using_backup, const std::string& version)
|
||||
if (!m_networking_module) {
|
||||
if (!m_load_error.has_error) {
|
||||
set_load_error(
|
||||
"Network library failed to load",
|
||||
_u8L("Network library failed to load"),
|
||||
"LoadLibrary/dlopen returned null",
|
||||
library
|
||||
);
|
||||
@@ -889,6 +890,12 @@ std::vector<NetworkLibraryVersionInfo> get_all_available_versions()
|
||||
return get_all_available_versions(plugin.is_loaded() ? plugin.get_version() : std::string());
|
||||
}
|
||||
|
||||
// Marks the AVAILABLE_NETWORK_VERSIONS warnings for extraction; bambu_networking.hpp is also built without the GUI.
|
||||
[[maybe_unused]] static const char* const network_version_warning_markers[] = {
|
||||
L("An older plug-in series. Features that need newer plug-in support, such as print-failure "
|
||||
"snapshots in the device error dialog, are unavailable."),
|
||||
};
|
||||
|
||||
std::vector<NetworkLibraryVersionInfo> get_all_available_versions(const std::string& loaded_version)
|
||||
{
|
||||
std::vector<NetworkLibraryVersionInfo> result;
|
||||
@@ -896,6 +903,8 @@ std::vector<NetworkLibraryVersionInfo> get_all_available_versions(const std::str
|
||||
|
||||
for (size_t i = 0; i < AVAILABLE_NETWORK_VERSIONS_COUNT; ++i) {
|
||||
result.push_back(NetworkLibraryVersionInfo::from_static(AVAILABLE_NETWORK_VERSIONS[i]));
|
||||
if (!result.back().warning.empty())
|
||||
result.back().warning = GUI::I18N::translate_utf8(result.back().warning);
|
||||
all_known_versions.insert(AVAILABLE_NETWORK_VERSIONS[i].version);
|
||||
}
|
||||
|
||||
|
||||
@@ -1497,7 +1497,7 @@ bool CalibUtils::check_printable_status_before_cali(const MachineObject *obj, co
|
||||
|
||||
for (const auto &cali_info : cali_infos.calib_datas) {
|
||||
wxString name = "";
|
||||
if (is_multi_extruder) { name = cali_info.extruder_id == MAIN_EXTRUDER_ID ? _L("right") + " ": _L("left") + " "; }
|
||||
if (is_multi_extruder) { name = cali_info.extruder_id == MAIN_EXTRUDER_ID ? _L("right") : _L("left"); }
|
||||
|
||||
float cali_diameter = cali_info.nozzle_diameter;
|
||||
int extruder_id = cali_info.extruder_id;
|
||||
@@ -1508,6 +1508,7 @@ bool CalibUtils::check_printable_status_before_cali(const MachineObject *obj, co
|
||||
|
||||
|
||||
if (is_approx(double(cali_info.nozzle_diameter), 0.2) && !obj->is_series_x()) {
|
||||
// TRN %s is "left" or "right".
|
||||
error_message = wxString::Format(_L("The nozzle diameter of %s extruder is 0.2mm which does not support automatic Flow Dynamics calibration."), name);
|
||||
return false;
|
||||
}
|
||||
@@ -1516,6 +1517,7 @@ bool CalibUtils::check_printable_status_before_cali(const MachineObject *obj, co
|
||||
NozzleFlowType nozzle_volume_type = obj->GetExtderSystem()->GetNozzleFlowType(extruder_id);
|
||||
if (!obj->GetExtderSystem()->NozzleDiameterMatchesOrUnknown(extruder_id, cali_info.nozzle_diameter)) {
|
||||
if (is_multi_extruder)
|
||||
// TRN %s is "left" or "right".
|
||||
error_message = wxString::Format(_L("The currently selected nozzle diameter of %s extruder does not match the actual nozzle diameter.\n"
|
||||
"Please click the Sync button above and restart the calibration."), name);
|
||||
else
|
||||
@@ -1526,6 +1528,7 @@ bool CalibUtils::check_printable_status_before_cali(const MachineObject *obj, co
|
||||
|
||||
if (nozzle_volume_type == NozzleFlowType::NONE_FLOWTYPE) {
|
||||
if (is_multi_extruder)
|
||||
// TRN %s is "left" or "right".
|
||||
error_message = wxString::Format(_L("Printer %s nozzle information has not been set. Please configure it before proceeding with the calibration."), name);
|
||||
else
|
||||
error_message = nozzle_not_set_text;
|
||||
@@ -1534,6 +1537,7 @@ bool CalibUtils::check_printable_status_before_cali(const MachineObject *obj, co
|
||||
|
||||
if (NozzleVolumeType(nozzle_volume_type - 1) != cali_info.nozzle_volume_type) {
|
||||
if (is_multi_extruder)
|
||||
// TRN %s is "left" or "right".
|
||||
error_message = wxString::Format(_L("The currently selected nozzle type of %s extruder does not match the actual printer nozzle type.\n"
|
||||
"Please click the Sync button above and restart the calibration."), name);
|
||||
else
|
||||
@@ -1558,7 +1562,7 @@ bool CalibUtils::check_printable_status_before_cali(const MachineObject *obj, co
|
||||
|
||||
for (const auto &cali_info : cali_infos) {
|
||||
wxString name = "";
|
||||
if (is_multi_extruder) { name = cali_info.extruder_id == MAIN_EXTRUDER_ID ? _L("right") + " " : _L("left") + " "; }
|
||||
if (is_multi_extruder) { name = cali_info.extruder_id == MAIN_EXTRUDER_ID ? _L("right") : _L("left"); }
|
||||
|
||||
if (cali_info.params.mode == CalibMode::Calib_Auto_PA_Line && !is_support_auto_pa_cali(cali_info.filament_prest->filament_id)) {
|
||||
error_message = _L("TPU 90A/TPU 85A is too soft and does not support automatic Flow Dynamics calibration.");
|
||||
|
||||
@@ -187,9 +187,10 @@ bool validate_local_api_response(const std::string& response_body, wxString& err
|
||||
message = parsed["msg"].get<std::string>();
|
||||
|
||||
if (message.empty())
|
||||
message = "Request failed";
|
||||
message = _u8L("Request failed");
|
||||
|
||||
error_msg = GUI::from_u8((boost::format("Flashforge local API error %1%: %2%") % result_code % message).str());
|
||||
// TRN %1% is the error code returned by the printer, %2% its error message.
|
||||
error_msg = GUI::from_u8((boost::format(_u8L("Flashforge local API error %1%: %2%")) % result_code % message).str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user