kopia lustrzana https://github.com/inkstitch/inkstitch
framework for translations (#55)
sets up all the plumbing to send strings to CrowdIn for translation and incorporate the resultspull/60/head
rodzic
1dd76646cc
commit
72d52dc317
|
@ -5,6 +5,7 @@
|
|||
*.tar.gz
|
||||
dist/
|
||||
build/
|
||||
locales/
|
||||
|
||||
# For development, I symlink into my clone, so I have to have a copy of libembroidery.
|
||||
libembroidery.py
|
||||
|
|
22
Makefile
22
Makefile
|
@ -5,10 +5,30 @@ VERSION:=$(TRAVIS_BRANCH)
|
|||
OS:=$(shell uname)
|
||||
ARCH:=$(shell uname -m)
|
||||
|
||||
dist: distclean
|
||||
dist: distclean locales
|
||||
bin/build-dist $(EXTENSIONS)
|
||||
cp *.inx dist
|
||||
mv locales dist/bin
|
||||
cd dist; tar zcf ../inkstitch-$(VERSION)-$(OS)-$(ARCH).tar.gz *
|
||||
|
||||
distclean:
|
||||
rm -rf build dist *.spec *.tar.gz
|
||||
|
||||
messages.po: embroider*.py inkstitch.py
|
||||
rm -f messages.po
|
||||
xgettext embroider*.py inkstitch.py
|
||||
|
||||
.PHONY: locales
|
||||
locales:
|
||||
# message files will look like this:
|
||||
# translations/messages-en_US.po
|
||||
if ls translations/*.po > /dev/null 2>&1; then \
|
||||
for po in translations/*.po; do \
|
||||
lang=$${po%.po}; \
|
||||
lang=$${lang#messages-}; \
|
||||
mkdir -p locales/$$lang/LC_MESSAGES/; \
|
||||
msgfmt $$po -o locales/$$lang/LC_MESSAGES/inkstitch.mo; \
|
||||
done; \
|
||||
else \
|
||||
mkdir locales; \
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
files:
|
||||
- source: messages.po
|
||||
translation: /translations/messages_%locale_with_underscore%.po
|
84
embroider.py
84
embroider.py
|
@ -35,20 +35,19 @@ import networkx
|
|||
from pprint import pformat
|
||||
|
||||
import inkstitch
|
||||
from inkstitch import cache, dbg, param, EmbroideryElement, get_nodes, SVG_POLYLINE_TAG, SVG_GROUP_TAG, PIXELS_PER_MM, get_viewbox_transform
|
||||
|
||||
from inkstitch import _, cache, dbg, param, EmbroideryElement, get_nodes, SVG_POLYLINE_TAG, SVG_GROUP_TAG, PIXELS_PER_MM, get_viewbox_transform
|
||||
|
||||
class Fill(EmbroideryElement):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Fill, self).__init__(*args, **kwargs)
|
||||
|
||||
@property
|
||||
@param('auto_fill', 'Manually routed fill stitching', type='toggle', inverse=True, default=True)
|
||||
@param('auto_fill', _('Manually routed fill stitching'), type='toggle', inverse=True, default=True)
|
||||
def auto_fill(self):
|
||||
return self.get_boolean_param('auto_fill', True)
|
||||
|
||||
@property
|
||||
@param('angle', 'Angle of lines of stitches', unit='deg', type='float', default=0)
|
||||
@param('angle', _('Angle of lines of stitches'), unit='deg', type='float', default=0)
|
||||
@cache
|
||||
def angle(self):
|
||||
return math.radians(self.get_float_param('angle', 0))
|
||||
|
@ -58,12 +57,12 @@ class Fill(EmbroideryElement):
|
|||
return self.get_style("fill")
|
||||
|
||||
@property
|
||||
@param('flip', 'Flip fill (start right-to-left)', type='boolean', default=False)
|
||||
@param('flip', _('Flip fill (start right-to-left)'), type='boolean', default=False)
|
||||
def flip(self):
|
||||
return self.get_boolean_param("flip", False)
|
||||
|
||||
@property
|
||||
@param('row_spacing_mm', 'Spacing between rows', unit='mm', type='float', default=0.25)
|
||||
@param('row_spacing_mm', _('Spacing between rows'), unit='mm', type='float', default=0.25)
|
||||
def row_spacing(self):
|
||||
return max(self.get_float_param("row_spacing_mm", 0.25), 0.01)
|
||||
|
||||
|
@ -72,12 +71,12 @@ class Fill(EmbroideryElement):
|
|||
return self.get_float_param("end_row_spacing_mm")
|
||||
|
||||
@property
|
||||
@param('max_stitch_length_mm', 'Maximum fill stitch length', unit='mm', type='float', default=3.0)
|
||||
@param('max_stitch_length_mm', _('Maximum fill stitch length'), unit='mm', type='float', default=3.0)
|
||||
def max_stitch_length(self):
|
||||
return max(self.get_float_param("max_stitch_length_mm", 3.0), 0.01)
|
||||
|
||||
@property
|
||||
@param('staggers', 'Stagger rows this many times before repeating', type='int', default=4)
|
||||
@param('staggers', _('Stagger rows this many times before repeating'), type='int', default=4)
|
||||
def staggers(self):
|
||||
return self.get_int_param("staggers", 4)
|
||||
|
||||
|
@ -371,7 +370,7 @@ class MaxQueueLengthExceeded(Exception):
|
|||
|
||||
class AutoFill(Fill):
|
||||
@property
|
||||
@param('auto_fill', 'Automatically routed fill stitching', type='toggle', default=True)
|
||||
@param('auto_fill', _('Automatically routed fill stitching'), type='toggle', default=True)
|
||||
def auto_fill(self):
|
||||
return self.get_boolean_param('auto_fill', True)
|
||||
|
||||
|
@ -390,17 +389,17 @@ class AutoFill(Fill):
|
|||
return False
|
||||
|
||||
@property
|
||||
@param('running_stitch_length_mm', 'Running stitch length (traversal between sections)', unit='mm', type='float', default=1.5)
|
||||
@param('running_stitch_length_mm', _('Running stitch length (traversal between sections)'), unit='mm', type='float', default=1.5)
|
||||
def running_stitch_length(self):
|
||||
return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01)
|
||||
|
||||
@property
|
||||
@param('fill_underlay', 'Underlay', type='toggle', group='AutoFill Underlay', default=False)
|
||||
@param('fill_underlay', _('Underlay'), type='toggle', group=_('AutoFill Underlay'), default=False)
|
||||
def fill_underlay(self):
|
||||
return self.get_boolean_param("fill_underlay", default=False)
|
||||
|
||||
@property
|
||||
@param('fill_underlay_angle', 'Fill angle (default: fill angle + 90 deg)', unit='deg', group='AutoFill Underlay', type='float')
|
||||
@param('fill_underlay_angle', _('Fill angle (default: fill angle + 90 deg)'), unit='deg', group=_('AutoFill Underlay'), type='float')
|
||||
@cache
|
||||
def fill_underlay_angle(self):
|
||||
underlay_angle = self.get_float_param("fill_underlay_angle")
|
||||
|
@ -411,13 +410,13 @@ class AutoFill(Fill):
|
|||
return self.angle + math.pi / 2.0
|
||||
|
||||
@property
|
||||
@param('fill_underlay_row_spacing_mm', 'Row spacing (default: 3x fill row spacing)', unit='mm', group='AutoFill Underlay', type='float')
|
||||
@param('fill_underlay_row_spacing_mm', _('Row spacing (default: 3x fill row spacing)'), unit='mm', group=_('AutoFill Underlay'), type='float')
|
||||
@cache
|
||||
def fill_underlay_row_spacing(self):
|
||||
return self.get_float_param("fill_underlay_row_spacing_mm") or self.row_spacing * 3
|
||||
|
||||
@property
|
||||
@param('fill_underlay_max_stitch_length_mm', 'Max stitch length', unit='mm', group='AutoFill Underlay', type='float')
|
||||
@param('fill_underlay_max_stitch_length_mm', _('Max stitch length'), unit='mm', group=_('AutoFill Underlay'), type='float')
|
||||
@cache
|
||||
def fill_underlay_max_stitch_length(self):
|
||||
return self.get_float_param("fill_underlay_max_stitch_length_mm") or self.max_stitch_length
|
||||
|
@ -538,7 +537,7 @@ class AutoFill(Fill):
|
|||
|
||||
|
||||
if not networkx.is_eulerian(graph):
|
||||
raise Exception("something went wrong: graph is not eulerian")
|
||||
raise Exception(_("Unable to autofill. This most often happens because your shape is made up of multiple sections that aren't connected."))
|
||||
|
||||
return graph
|
||||
|
||||
|
@ -713,7 +712,7 @@ class AutoFill(Fill):
|
|||
result = self.find_loop(graph, nodes_visited)
|
||||
|
||||
if not result:
|
||||
print >> sys.stderr, "Unexpected error filling region. Please send your SVG to lexelby@github."
|
||||
print >> sys.stderr, _("Unexpected error while generating fill stitches. Please send your SVG file to lexelby@github.")
|
||||
break
|
||||
|
||||
loop, segments = result
|
||||
|
@ -882,7 +881,7 @@ class AutoFill(Fill):
|
|||
|
||||
class Stroke(EmbroideryElement):
|
||||
@property
|
||||
@param('satin_column', 'Satin along paths', type='toggle', inverse=True)
|
||||
@param('satin_column', _('Satin stitch along paths'), type='toggle', inverse=True)
|
||||
def satin_column(self):
|
||||
return self.get_boolean_param("satin_column")
|
||||
|
||||
|
@ -905,18 +904,18 @@ class Stroke(EmbroideryElement):
|
|||
return self.get_style("stroke-dasharray") is not None
|
||||
|
||||
@property
|
||||
@param('running_stitch_length_mm', 'Running stitch length', unit='mm', type='float', default=1.5)
|
||||
@param('running_stitch_length_mm', _('Running stitch length'), unit='mm', type='float', default=1.5)
|
||||
def running_stitch_length(self):
|
||||
return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01)
|
||||
|
||||
@property
|
||||
@param('zigzag_spacing_mm', 'Zig-zag spacing (peak-to-peak)', unit='mm', type='float', default=0.4)
|
||||
@param('zigzag_spacing_mm', _('Zig-zag spacing (peak-to-peak)'), unit='mm', type='float', default=0.4)
|
||||
@cache
|
||||
def zigzag_spacing(self):
|
||||
return max(self.get_float_param("zigzag_spacing_mm", 0.4), 0.01)
|
||||
|
||||
@property
|
||||
@param('repeats', 'Repeats', type='int', default="1")
|
||||
@param('repeats', _('Repeats'), type='int', default="1")
|
||||
def repeats(self):
|
||||
return self.get_int_param("repeats", 1)
|
||||
|
||||
|
@ -997,7 +996,7 @@ class SatinColumn(EmbroideryElement):
|
|||
super(SatinColumn, self).__init__(*args, **kwargs)
|
||||
|
||||
@property
|
||||
@param('satin_column', 'Custom satin column', type='toggle')
|
||||
@param('satin_column', _('Custom satin column'), type='toggle')
|
||||
def satin_column(self):
|
||||
return self.get_boolean_param("satin_column")
|
||||
|
||||
|
@ -1006,13 +1005,13 @@ class SatinColumn(EmbroideryElement):
|
|||
return self.get_style("stroke")
|
||||
|
||||
@property
|
||||
@param('zigzag_spacing_mm', 'Zig-zag spacing (peak-to-peak)', unit='mm', type='float', default=0.4)
|
||||
@param('zigzag_spacing_mm', _('Zig-zag spacing (peak-to-peak)'), unit='mm', type='float', default=0.4)
|
||||
def zigzag_spacing(self):
|
||||
# peak-to-peak distance between zigzags
|
||||
return max(self.get_float_param("zigzag_spacing_mm", 0.4), 0.01)
|
||||
|
||||
@property
|
||||
@param('pull_compensation_mm', 'Pull compensation', unit='mm', type='float')
|
||||
@param('pull_compensation_mm', _('Pull compensation'), unit='mm', type='float')
|
||||
def pull_compensation(self):
|
||||
# In satin stitch, the stitches have a tendency to pull together and
|
||||
# narrow the entire column. We can compensate for this by stitching
|
||||
|
@ -1020,47 +1019,47 @@ class SatinColumn(EmbroideryElement):
|
|||
return self.get_float_param("pull_compensation_mm", 0)
|
||||
|
||||
@property
|
||||
@param('contour_underlay', 'Contour underlay', type='toggle', group='Contour Underlay')
|
||||
@param('contour_underlay', _('Contour underlay'), type='toggle', group=_('Contour Underlay'))
|
||||
def contour_underlay(self):
|
||||
# "Contour underlay" is stitching just inside the rectangular shape
|
||||
# of the satin column; that is, up one side and down the other.
|
||||
return self.get_boolean_param("contour_underlay")
|
||||
|
||||
@property
|
||||
@param('contour_underlay_stitch_length_mm', 'Stitch length', unit='mm', group='Contour Underlay', type='float', default=1.5)
|
||||
@param('contour_underlay_stitch_length_mm', _('Stitch length'), unit='mm', group=_('Contour Underlay'), type='float', default=1.5)
|
||||
def contour_underlay_stitch_length(self):
|
||||
return max(self.get_float_param("contour_underlay_stitch_length_mm", 1.5), 0.01)
|
||||
|
||||
@property
|
||||
@param('contour_underlay_inset_mm', 'Contour underlay inset amount', unit='mm', group='Contour Underlay', type='float', default=0.4)
|
||||
@param('contour_underlay_inset_mm', _('Contour underlay inset amount'), unit='mm', group=_('Contour Underlay'), type='float', default=0.4)
|
||||
def contour_underlay_inset(self):
|
||||
# how far inside the edge of the column to stitch the underlay
|
||||
return self.get_float_param("contour_underlay_inset_mm", 0.4)
|
||||
|
||||
@property
|
||||
@param('center_walk_underlay', 'Center-walk underlay', type='toggle', group='Center-Walk Underlay')
|
||||
@param('center_walk_underlay', _('Center-walk underlay'), type='toggle', group=_('Center-Walk Underlay'))
|
||||
def center_walk_underlay(self):
|
||||
# "Center walk underlay" is stitching down and back in the centerline
|
||||
# between the two sides of the satin column.
|
||||
return self.get_boolean_param("center_walk_underlay")
|
||||
|
||||
@property
|
||||
@param('center_walk_underlay_stitch_length_mm', 'Stitch length', unit='mm', group='Center-Walk Underlay', type='float', default=1.5)
|
||||
@param('center_walk_underlay_stitch_length_mm', _('Stitch length'), unit='mm', group=_('Center-Walk Underlay'), type='float', default=1.5)
|
||||
def center_walk_underlay_stitch_length(self):
|
||||
return max(self.get_float_param("center_walk_underlay_stitch_length_mm", 1.5), 0.01)
|
||||
|
||||
@property
|
||||
@param('zigzag_underlay', 'Zig-zag underlay', type='toggle', group='Zig-zag Underlay')
|
||||
@param('zigzag_underlay', _('Zig-zag underlay'), type='toggle', group=_('Zig-zag Underlay'))
|
||||
def zigzag_underlay(self):
|
||||
return self.get_boolean_param("zigzag_underlay")
|
||||
|
||||
@property
|
||||
@param('zigzag_underlay_spacing_mm', 'Zig-Zag spacing (peak-to-peak)', unit='mm', group='Zig-zag Underlay', type='float', default=3)
|
||||
@param('zigzag_underlay_spacing_mm', _('Zig-Zag spacing (peak-to-peak)'), unit='mm', group=_('Zig-zag Underlay'), type='float', default=3)
|
||||
def zigzag_underlay_spacing(self):
|
||||
return max(self.get_float_param("zigzag_underlay_spacing_mm", 3), 0.01)
|
||||
|
||||
@property
|
||||
@param('zigzag_underlay_inset_mm', 'Inset amount (default: half of contour underlay inset)', unit='mm', group='Zig-zag Underlay', type='float')
|
||||
@param('zigzag_underlay_inset_mm', _('Inset amount (default: half of contour underlay inset)'), unit='mm', group=_('Zig-zag Underlay'), type='float')
|
||||
def zigzag_underlay_inset(self):
|
||||
# how far in from the edge of the satin the points in the zigzags
|
||||
# should be
|
||||
|
@ -1106,14 +1105,16 @@ class SatinColumn(EmbroideryElement):
|
|||
|
||||
for rail in rails:
|
||||
if not rail.is_simple:
|
||||
self.fatal("One or more rails crosses itself, and this is not allowed. Please split into multiple satin columns.")
|
||||
self.fatal(_("One or more rails crosses itself, and this is not allowed. Please split into multiple satin columns."))
|
||||
|
||||
# handle null intersections here?
|
||||
linestrings = shapely.ops.split(rail, rungs)
|
||||
|
||||
print >> dbg, "rails and rungs", [str(rail) for rail in rails], [str(rung) for rung in rungs]
|
||||
if len(linestrings.geoms) < len(rungs.geoms) + 1:
|
||||
print >> dbg, [str(rail) for rail in rails], [str(rung) for rung in rungs]
|
||||
self.fatal("Expected %d linestrings, got %d" % (len(rungs.geoms) + 1, len(linestrings.geoms)))
|
||||
self.fatal(_("satin column: One or more of the rungs doesn't intersect both rails.") + " " + _("Each rail should intersect both rungs once."))
|
||||
elif len(linestrings.geoms) > len(rungs.geoms) + 1:
|
||||
self.fatal(_("satin column: One or more of the rungs intersects the rails more than once.") + " " + _("Each rail should intersect both rungs once."))
|
||||
|
||||
paths = [[inkstitch.Point(*coord) for coord in ls.coords] for ls in linestrings.geoms]
|
||||
result.append(paths)
|
||||
|
@ -1154,11 +1155,12 @@ class SatinColumn(EmbroideryElement):
|
|||
node_id = self.node.get("id")
|
||||
|
||||
if self.get_style("fill") is not None:
|
||||
self.fatal("satin column: object %s has a fill (but should not)" % node_id)
|
||||
self.fatal(_("satin column: object %s has a fill (but should not)") % node_id)
|
||||
|
||||
if len(self.csp) == 2:
|
||||
if len(self.csp[0]) != len(self.csp[1]):
|
||||
self.fatal("satin column: object %s has two paths with an unequal number of points (%s and %s)" % (node_id, len(self.csp[0]), len(self.csp[1])))
|
||||
self.fatal(_("satin column: object %(id)s has two paths with an unequal number of points (%(length1)d and %(length2)d)") % \
|
||||
dict(id=node_id, length1=len(self.csp[0]), length2=len(self.csp[1])))
|
||||
|
||||
def offset_points(self, pos1, pos2, offset_px):
|
||||
# Expand or contract two points about their midpoint. This is
|
||||
|
@ -1690,7 +1692,7 @@ class Embroider(inkex.Effect):
|
|||
action="store", type="int",
|
||||
dest="max_backups", default=5,
|
||||
help="Max number of backups of output files to keep.")
|
||||
self.OptionParser.usage += "\n\nSeeing a 'no such option' message? Please restart Inkscape to fix."
|
||||
self.OptionParser.usage += _("\n\nSeeing a 'no such option' message? Please restart Inkscape to fix.")
|
||||
|
||||
def get_output_path(self):
|
||||
if self.options.output_file:
|
||||
|
@ -1738,10 +1740,10 @@ class Embroider(inkex.Effect):
|
|||
|
||||
if not self.elements:
|
||||
if self.selected:
|
||||
inkex.errormsg("No embroiderable paths selected.")
|
||||
inkex.errormsg(_("No embroiderable paths selected."))
|
||||
else:
|
||||
inkex.errormsg("No embroiderable paths found in document.")
|
||||
inkex.errormsg("Tip: use Path -> Object to Path to convert non-paths before embroidering.")
|
||||
inkex.errormsg(_("No embroiderable paths found in document."))
|
||||
inkex.errormsg(_("Tip: use Path -> Object to Path to convert non-paths before embroidering."))
|
||||
return
|
||||
|
||||
if self.options.hide_layers:
|
||||
|
@ -1753,7 +1755,7 @@ class Embroider(inkex.Effect):
|
|||
|
||||
new_layer = inkex.etree.SubElement(self.document.getroot(), SVG_GROUP_TAG, {})
|
||||
new_layer.set('id', self.uniqueId("embroidery"))
|
||||
new_layer.set(inkex.addNS('label', 'inkscape'), 'Embroidery')
|
||||
new_layer.set(inkex.addNS('label', 'inkscape'), _('Embroidery'))
|
||||
new_layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
|
||||
|
||||
emit_inkscape(new_layer, stitches)
|
||||
|
|
|
@ -13,12 +13,14 @@ import wx
|
|||
from wx.lib.scrolledpanel import ScrolledPanel
|
||||
from collections import defaultdict
|
||||
import inkex
|
||||
from inkstitch import Param, EmbroideryElement, get_nodes
|
||||
import inkstitch
|
||||
from inkstitch import _, Param, EmbroideryElement, get_nodes
|
||||
from embroider import Fill, AutoFill, Stroke, SatinColumn
|
||||
from functools import partial
|
||||
from itertools import groupby
|
||||
from embroider_simulate import EmbroiderySimulator
|
||||
|
||||
|
||||
def presets_path():
|
||||
try:
|
||||
import appdirs
|
||||
|
@ -237,17 +239,22 @@ class ParamsTab(ScrolledPanel):
|
|||
preset[name] = input.GetValue()
|
||||
|
||||
def update_description(self):
|
||||
description = "These settings will be applied to %d object%s." % \
|
||||
(len(self.nodes), "s" if len(self.nodes) != 1 else "")
|
||||
if len(self.nodes) == 1:
|
||||
description = _("These settings will be applied to 1 object.")
|
||||
else:
|
||||
description = _("These settings will be applied to %d objects.") % len(self.nodes)
|
||||
|
||||
if any(len(param.values) > 1 for param in self.params):
|
||||
description += "\n • Some settings had different values across objects. Select a value from the dropdown or enter a new one."
|
||||
description += "\n • " + _("Some settings had different values across objects. Select a value from the dropdown or enter a new one.")
|
||||
|
||||
if self.dependent_tabs:
|
||||
description += "\n • Disabling this tab will disable the following %d tabs." % len(self.dependent_tabs)
|
||||
if len(self.dependent_tabs) == 1:
|
||||
description += "\n • " + _("Disabling this tab will disable the following %d tabs.") % len(self.dependent_tabs)
|
||||
else:
|
||||
description += "\n • " + _("Disabling this tab will disable the following tab.")
|
||||
|
||||
if self.paired_tab:
|
||||
description += "\n • Enabling this tab will disable %s and vice-versa." % self.paired_tab.name
|
||||
description += "\n • " + _("Enabling this tab will disable %s and vice-versa.") % self.paired_tab.name
|
||||
|
||||
self.description_text = description
|
||||
|
||||
|
@ -277,7 +284,7 @@ class ParamsTab(ScrolledPanel):
|
|||
# just to add space around the settings
|
||||
box = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
summary_box = wx.StaticBox(self, wx.ID_ANY, label="Inkscape objects")
|
||||
summary_box = wx.StaticBox(self, wx.ID_ANY, label=_("Inkscape objects"))
|
||||
sizer = wx.StaticBoxSizer(summary_box, wx.HORIZONTAL)
|
||||
# sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.description = wx.StaticText(self, style=wx.TE_WORDWRAP)
|
||||
|
@ -335,7 +342,7 @@ class SettingsFrame(wx.Frame):
|
|||
self.tabs_factory = kwargs.pop('tabs_factory', [])
|
||||
self.cancel_hook = kwargs.pop('on_cancel', None)
|
||||
wx.Frame.__init__(self, None, wx.ID_ANY,
|
||||
"Embroidery Params"
|
||||
_("Embroidery Params")
|
||||
)
|
||||
self.notebook = wx.Notebook(self, wx.ID_ANY)
|
||||
self.tabs = self.tabs_factory(self.notebook)
|
||||
|
@ -349,31 +356,31 @@ class SettingsFrame(wx.Frame):
|
|||
|
||||
wx.CallLater(1000, self.update_simulator)
|
||||
|
||||
self.presets_box = wx.StaticBox(self, wx.ID_ANY, label="Presets")
|
||||
self.presets_box = wx.StaticBox(self, wx.ID_ANY, label=_("Presets"))
|
||||
|
||||
self.preset_chooser = wx.ComboBox(self, wx.ID_ANY)
|
||||
self.update_preset_list()
|
||||
|
||||
self.load_preset_button = wx.Button(self, wx.ID_ANY, "Load")
|
||||
self.load_preset_button = wx.Button(self, wx.ID_ANY, _("Load"))
|
||||
self.load_preset_button.Bind(wx.EVT_BUTTON, self.load_preset)
|
||||
|
||||
self.add_preset_button = wx.Button(self, wx.ID_ANY, "Add")
|
||||
self.add_preset_button = wx.Button(self, wx.ID_ANY, _("Add"))
|
||||
self.add_preset_button.Bind(wx.EVT_BUTTON, self.add_preset)
|
||||
|
||||
self.overwrite_preset_button = wx.Button(self, wx.ID_ANY, "Overwrite")
|
||||
self.overwrite_preset_button = wx.Button(self, wx.ID_ANY, _("Overwrite"))
|
||||
self.overwrite_preset_button.Bind(wx.EVT_BUTTON, self.overwrite_preset)
|
||||
|
||||
self.delete_preset_button = wx.Button(self, wx.ID_ANY, "Delete")
|
||||
self.delete_preset_button = wx.Button(self, wx.ID_ANY, _("Delete"))
|
||||
self.delete_preset_button.Bind(wx.EVT_BUTTON, self.delete_preset)
|
||||
|
||||
self.cancel_button = wx.Button(self, wx.ID_ANY, "Cancel")
|
||||
self.cancel_button = wx.Button(self, wx.ID_ANY, _("Cancel"))
|
||||
self.cancel_button.Bind(wx.EVT_BUTTON, self.cancel)
|
||||
self.Bind(wx.EVT_CLOSE, self.cancel)
|
||||
|
||||
self.use_last_button = wx.Button(self, wx.ID_ANY, "Use Last Settings")
|
||||
self.use_last_button = wx.Button(self, wx.ID_ANY, _("Use Last Settings"))
|
||||
self.use_last_button.Bind(wx.EVT_BUTTON, self.use_last)
|
||||
|
||||
self.apply_button = wx.Button(self, wx.ID_ANY, "Apply and Quit")
|
||||
self.apply_button = wx.Button(self, wx.ID_ANY, _("Apply and Quit"))
|
||||
self.apply_button.Bind(wx.EVT_BUTTON, self.apply)
|
||||
|
||||
self.__set_properties()
|
||||
|
@ -418,7 +425,7 @@ class SettingsFrame(wx.Frame):
|
|||
max_height = screen_rect.GetHeight()
|
||||
|
||||
try:
|
||||
self.simulate_window = EmbroiderySimulator(None, -1, "Embroidery Simulator",
|
||||
self.simulate_window = EmbroiderySimulator(None, -1, _("Preview"),
|
||||
simulator_pos,
|
||||
size=(300, 300),
|
||||
patches=patches,
|
||||
|
@ -432,11 +439,11 @@ class SettingsFrame(wx.Frame):
|
|||
try:
|
||||
# a window may have been created, so we need to destroy it
|
||||
# or the app will never exit
|
||||
wx.Window.FindWindowByName("Embroidery Simulator").Destroy()
|
||||
wx.Window.FindWindowByName("Preview").Destroy()
|
||||
except:
|
||||
pass
|
||||
|
||||
info_dialog(self, error, "Internal Error")
|
||||
info_dialog(self, error, _("Internal Error"))
|
||||
|
||||
self.simulate_window.Show()
|
||||
wx.CallLater(10, self.Raise)
|
||||
|
@ -489,13 +496,13 @@ class SettingsFrame(wx.Frame):
|
|||
if preset_name:
|
||||
return preset_name
|
||||
else:
|
||||
info_dialog(self, "Please enter or select a preset name first.", caption='Preset')
|
||||
info_dialog(self, _("Please enter or select a preset name first."), caption=_('Preset'))
|
||||
return
|
||||
|
||||
def check_and_load_preset(self, preset_name):
|
||||
preset = load_preset(preset_name)
|
||||
if not preset:
|
||||
info_dialog(self, 'Preset "%s" not found.' % preset_name, caption='Preset')
|
||||
info_dialog(self, _('Preset "%s" not found.') % preset_name, caption=_('Preset'))
|
||||
|
||||
return preset
|
||||
|
||||
|
@ -523,7 +530,7 @@ class SettingsFrame(wx.Frame):
|
|||
return
|
||||
|
||||
if not overwrite and load_preset(preset_name):
|
||||
info_dialog(self, 'Preset "%s" already exists. Please use another name or press "Overwrite"' % preset_name, caption='Preset')
|
||||
info_dialog(self, _('Preset "%s" already exists. Please use another name or press "Overwrite"') % preset_name, caption=_('Preset'))
|
||||
|
||||
save_preset(preset_name, self.get_preset_data())
|
||||
self.update_preset_list()
|
||||
|
@ -596,7 +603,6 @@ class SettingsFrame(wx.Frame):
|
|||
|
||||
def __set_properties(self):
|
||||
# begin wxGlade: MyFrame.__set_properties
|
||||
self.SetTitle("Embroidery Parameters")
|
||||
self.notebook.SetMinSize((800, 600))
|
||||
self.preset_chooser.SetSelection(-1)
|
||||
# end wxGlade
|
||||
|
|
|
@ -6,8 +6,10 @@ import inkex
|
|||
import simplestyle
|
||||
import colorsys
|
||||
|
||||
import inkstitch
|
||||
from inkstitch import PIXELS_PER_MM
|
||||
from embroider import patches_to_stitches, get_elements, elements_to_patches
|
||||
from embroider import _, patches_to_stitches, get_elements, elements_to_patches
|
||||
|
||||
|
||||
class EmbroiderySimulator(wx.Frame):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -298,7 +300,7 @@ class SimulateEffect(inkex.Effect):
|
|||
def effect(self):
|
||||
patches = elements_to_patches(get_elements(self))
|
||||
app = wx.App()
|
||||
frame = EmbroiderySimulator(None, -1, "Embroidery Simulation", wx.DefaultPosition, size=(1000, 1000), patches=patches)
|
||||
frame = EmbroiderySimulator(None, -1, _("Embroidery Simulation"), wx.DefaultPosition, size=(1000, 1000), patches=patches)
|
||||
app.SetTopWindow(frame)
|
||||
frame.Show()
|
||||
wx.CallAfter(frame.go)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Files in this directory are meant to be symlinked or copied into your local clone's .git/hooks directory.
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
make messages.po | grep -v 'is up to date\.$'
|
||||
git add messages.po
|
32
inkstitch.py
32
inkstitch.py
|
@ -1,7 +1,9 @@
|
|||
#!/usr/bin/env python
|
||||
# http://www.achatina.de/sewing/main/TECHNICL.HTM
|
||||
|
||||
import os
|
||||
import sys
|
||||
import gettext
|
||||
from copy import deepcopy
|
||||
import math
|
||||
import libembroidery
|
||||
|
@ -31,10 +33,28 @@ EMBROIDERABLE_TAGS = (SVG_PATH_TAG, SVG_POLYLINE_TAG)
|
|||
|
||||
dbg = open("/tmp/embroider-debug.txt", "w")
|
||||
|
||||
_ = lambda message: message
|
||||
|
||||
# simplify use of lru_cache decorator
|
||||
def cache(*args, **kwargs):
|
||||
return lru_cache(maxsize=None)(*args, **kwargs)
|
||||
|
||||
def localize():
|
||||
if getattr(sys, 'frozen', False):
|
||||
# we are in a pyinstaller installation
|
||||
locale_dir = sys._MEIPASS
|
||||
else:
|
||||
locale_dir = os.path.dirname(__file__)
|
||||
|
||||
locale_dir = os.path.join(locale_dir, 'locales')
|
||||
|
||||
translation = gettext.translation("inkstitch", locale_dir, fallback=True)
|
||||
|
||||
global _
|
||||
_ = translation.gettext
|
||||
|
||||
localize()
|
||||
|
||||
# cribbed from inkscape-silhouette
|
||||
def parse_length_with_units( str ):
|
||||
|
||||
|
@ -71,7 +91,7 @@ def parse_length_with_units( str ):
|
|||
try:
|
||||
v = float( s )
|
||||
except:
|
||||
raise ValueError("parseLengthWithUnits: unknown unit %s" % s)
|
||||
raise ValueError(_("parseLengthWithUnits: unknown unit %s") % s)
|
||||
|
||||
return v, u
|
||||
|
||||
|
@ -95,7 +115,7 @@ def convert_length(length):
|
|||
# open an old document, inkscape will add a viewbox for you.
|
||||
return value * 96
|
||||
|
||||
raise ValueError("Unknown unit: %s" % units)
|
||||
raise ValueError(_("Unknown unit: %s") % units)
|
||||
|
||||
|
||||
@cache
|
||||
|
@ -298,8 +318,8 @@ class EmbroideryElement(object):
|
|||
|
||||
@property
|
||||
@param('trim_after',
|
||||
'TRIM after',
|
||||
tooltip='Trim thread after this object (for supported machines and file formats)',
|
||||
_('TRIM after'),
|
||||
tooltip=_('Trim thread after this object (for supported machines and file formats)'),
|
||||
type='boolean',
|
||||
default=False,
|
||||
sort_index=1000)
|
||||
|
@ -308,8 +328,8 @@ class EmbroideryElement(object):
|
|||
|
||||
@property
|
||||
@param('stop_after',
|
||||
'STOP after',
|
||||
tooltip='Add STOP instruction after this object (for supported machines and file formats)',
|
||||
_('STOP after'),
|
||||
tooltip=_('Add STOP instruction after this object (for supported machines and file formats)'),
|
||||
type='boolean',
|
||||
default=False,
|
||||
sort_index=1000)
|
||||
|
|
|
@ -0,0 +1,329 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-02-04 16:24-0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: embroider.py:45
|
||||
msgid "Manually routed fill stitching"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:50
|
||||
msgid "Angle of lines of stitches"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:60
|
||||
msgid "Flip fill (start right-to-left)"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:65
|
||||
msgid "Spacing between rows"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:74
|
||||
msgid "Maximum fill stitch length"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:79
|
||||
msgid "Stagger rows this many times before repeating"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:373
|
||||
msgid "Automatically routed fill stitching"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:392
|
||||
msgid "Running stitch length (traversal between sections)"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:397
|
||||
msgid "Underlay"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:397 embroider.py:402 embroider.py:413 embroider.py:419
|
||||
msgid "AutoFill Underlay"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:402
|
||||
msgid "Fill angle (default: fill angle + 90 deg)"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:413
|
||||
msgid "Row spacing (default: 3x fill row spacing)"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:419
|
||||
msgid "Max stitch length"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:540
|
||||
msgid ""
|
||||
"Unable to autofill. This most often happens because your shape is made up "
|
||||
"of multiple sections that aren't connected."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:715
|
||||
msgid ""
|
||||
"Unexpected error while generating fill stitches. Please send your SVG file "
|
||||
"to lexelby@github."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:884
|
||||
msgid "Satin stitch along paths"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:907
|
||||
msgid "Running stitch length"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:912 embroider.py:1008
|
||||
msgid "Zig-zag spacing (peak-to-peak)"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:918
|
||||
msgid "Repeats"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:999
|
||||
msgid "Custom satin column"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1014
|
||||
msgid "Pull compensation"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1022
|
||||
msgid "Contour underlay"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1022 embroider.py:1029 embroider.py:1034
|
||||
msgid "Contour Underlay"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1029 embroider.py:1047
|
||||
msgid "Stitch length"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1034
|
||||
msgid "Contour underlay inset amount"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1040
|
||||
msgid "Center-walk underlay"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1040 embroider.py:1047
|
||||
msgid "Center-Walk Underlay"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1052
|
||||
msgid "Zig-zag underlay"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1052 embroider.py:1057 embroider.py:1062
|
||||
msgid "Zig-zag Underlay"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1057
|
||||
msgid "Zig-Zag spacing (peak-to-peak)"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1062
|
||||
msgid "Inset amount (default: half of contour underlay inset)"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1108
|
||||
msgid ""
|
||||
"One or more rails crosses itself, and this is not allowed. Please split "
|
||||
"into multiple satin columns."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1115
|
||||
msgid "satin column: One or more of the rungs doesn't intersect both rails."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1115 embroider.py:1117
|
||||
msgid "Each rail should intersect both rungs once."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1117
|
||||
msgid ""
|
||||
"satin column: One or more of the rungs intersects the rails more than once."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1158
|
||||
#, python-format
|
||||
msgid "satin column: object %s has a fill (but should not)"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1162
|
||||
#, python-format
|
||||
msgid ""
|
||||
"satin column: object %(id)s has two paths with an unequal number of points "
|
||||
"(%(length1)d and %(length2)d)"
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1695
|
||||
msgid ""
|
||||
"\n"
|
||||
"\n"
|
||||
"Seeing a 'no such option' message? Please restart Inkscape to fix."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1743
|
||||
msgid "No embroiderable paths selected."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1745
|
||||
msgid "No embroiderable paths found in document."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1746
|
||||
msgid ""
|
||||
"Tip: use Path -> Object to Path to convert non-paths before embroidering."
|
||||
msgstr ""
|
||||
|
||||
#: embroider.py:1758
|
||||
msgid "Embroidery"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:243
|
||||
msgid "These settings will be applied to 1 object."
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:245
|
||||
#, python-format
|
||||
msgid "These settings will be applied to %d objects."
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:248
|
||||
msgid ""
|
||||
"Some settings had different values across objects. Select a value from the "
|
||||
"dropdown or enter a new one."
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:252
|
||||
#, python-format
|
||||
msgid "Disabling this tab will disable the following %d tabs."
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:254
|
||||
msgid "Disabling this tab will disable the following tab."
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:257
|
||||
#, python-format
|
||||
msgid "Enabling this tab will disable %s and vice-versa."
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:287
|
||||
msgid "Inkscape objects"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:345
|
||||
msgid "Embroidery Params"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:359
|
||||
msgid "Presets"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:364
|
||||
msgid "Load"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:367
|
||||
msgid "Add"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:370
|
||||
msgid "Overwrite"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:373
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:376
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:380
|
||||
msgid "Use Last Settings"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:383
|
||||
msgid "Apply and Quit"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:428
|
||||
msgid "Preview"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:446
|
||||
msgid "Internal Error"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:499
|
||||
msgid "Please enter or select a preset name first."
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:499 embroider_params.py:505 embroider_params.py:533
|
||||
msgid "Preset"
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:505
|
||||
#, python-format
|
||||
msgid "Preset \"%s\" not found."
|
||||
msgstr ""
|
||||
|
||||
#: embroider_params.py:533
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Preset \"%s\" already exists. Please use another name or press \"Overwrite\""
|
||||
msgstr ""
|
||||
|
||||
#: embroider_simulate.py:303
|
||||
msgid "Embroidery Simulation"
|
||||
msgstr ""
|
||||
|
||||
#: inkstitch.py:94
|
||||
#, python-format
|
||||
msgid "parseLengthWithUnits: unknown unit %s"
|
||||
msgstr ""
|
||||
|
||||
#: inkstitch.py:118
|
||||
#, python-format
|
||||
msgid "Unknown unit: %s"
|
||||
msgstr ""
|
||||
|
||||
#: inkstitch.py:321
|
||||
msgid "TRIM after"
|
||||
msgstr ""
|
||||
|
||||
#: inkstitch.py:322
|
||||
msgid "Trim thread after this object (for supported machines and file formats)"
|
||||
msgstr ""
|
||||
|
||||
#: inkstitch.py:331
|
||||
msgid "STOP after"
|
||||
msgstr ""
|
||||
|
||||
#: inkstitch.py:332
|
||||
msgid ""
|
||||
"Add STOP instruction after this object (for supported machines and file "
|
||||
"formats)"
|
||||
msgstr ""
|
Ładowanie…
Reference in New Issue