diff --git a/corepkgs/derivation.nix b/corepkgs/derivation.nix
index 851c8d3ea55a0c10836789649496dcf930c39915..c0fbe8082cd3b1252e7c7b5310eb3a33c6733a36 100644
--- a/corepkgs/derivation.nix
+++ b/corepkgs/derivation.nix
@@ -1,5 +1,5 @@
-/* This is the implementation of the 'derivation' builtin function.
-   It's actually a wrapper around the 'derivationStrict' primop. */
+/* This is the implementation of the ‘derivation’ builtin function.
+   It's actually a wrapper around the ‘derivationStrict’ primop. */
 
 drvAttrs @ { outputs ? [ "out" ], ... }:
 
diff --git a/mk/functions.mk b/mk/functions.mk
index fdeb92a8ad11f60eac3221eba470be524149173b..c48775db8c3b498ff6a6db0b43c5a9cccb5217d8 100644
--- a/mk/functions.mk
+++ b/mk/functions.mk
@@ -1,9 +1,9 @@
 # Utility function for recursively finding files, e.g.
-# '$(call rwildcard, path/to/dir, *.c *.h)'.
+# ‘$(call rwildcard, path/to/dir, *.c *.h)’.
 rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
 
 # Given a file name, produce the corresponding dependency file
-# (e.g. 'foo/bar.o' becomes 'foo/.bar.o.dep').
+# (e.g. ‘foo/bar.o’ becomes ‘foo/.bar.o.dep’).
 filename-to-dep = $(dir $1).$(notdir $1).dep
 
 # Return the full path to a program by looking it up in $PATH, or the
diff --git a/mk/libraries.mk b/mk/libraries.mk
index 8f60b0e001e1bbef170563826d6de3496aee1b5a..3cd7a53107bd0ce9c3029e3697471f033b6e1dd2 100644
--- a/mk/libraries.mk
+++ b/mk/libraries.mk
@@ -11,9 +11,9 @@ else
 endif
 
 # Build a library with symbolic name $(1).  The library is defined by
-# various variables prefixed by '$(1)_':
+# various variables prefixed by ‘$(1)_’:
 #
-# - $(1)_NAME: the name of the library (e.g. 'libfoo'); defaults to
+# - $(1)_NAME: the name of the library (e.g. ‘libfoo’); defaults to
 #   $(1).
 #
 # - $(1)_DIR: the directory where the (non-installed) library will be
@@ -45,7 +45,7 @@ endif
 # - $(1)_INSTALL_DIR: the directory where the library will be
 #   installed.  Defaults to $(libdir).
 #
-# - BUILD_SHARED_LIBS: if equal to '1', a dynamic library will be
+# - BUILD_SHARED_LIBS: if equal to ‘1’, a dynamic library will be
 #   built, otherwise a static library.
 define build-library
   $(1)_NAME ?= $(1)
diff --git a/mk/programs.mk b/mk/programs.mk
index e77cda1e08f49bcd254e2a59a6a164eda0b31b53..3ac64494e3a5ac582667483833f9e51b6718d556 100644
--- a/mk/programs.mk
+++ b/mk/programs.mk
@@ -1,7 +1,7 @@
 programs-list :=
 
 # Build a program with symbolic name $(1).  The program is defined by
-# various variables prefixed by '$(1)_':
+# various variables prefixed by ‘$(1)_’:
 #
 # - $(1)_DIR: the directory where the (non-installed) program will be
 #   placed.
diff --git a/mk/templates.mk b/mk/templates.mk
index 850fc8f17cffc6063de878e9b137cd5c032c32c3..c7ac7afbff27b221e55497b430e10083e60df638 100644
--- a/mk/templates.mk
+++ b/mk/templates.mk
@@ -1,7 +1,7 @@
 template-files :=
 
 # Create the file $(1) from $(1).in by running config.status (which
-# substitutes all '@var@' variables set by the configure script).
+# substitutes all ‘@var@’ variables set by the configure script).
 define instantiate-template
 
   clean-files += $(1)
diff --git a/mk/tests.mk b/mk/tests.mk
index e0d9ff146a68dfa84477e4145974923fbb75ac80..004a480286162482aaefa9d7ac6afd0c3aa97734 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -1,4 +1,4 @@
-# Run program $1 as part of 'make installcheck'.
+# Run program $1 as part of ‘make installcheck’.
 define run-install-test
 
   installcheck: $1
diff --git a/perl/lib/Nix/Config.pm.in b/perl/lib/Nix/Config.pm.in
index c23e1ae4bee2ca25004676ee7884c072fdeb84c4..3575d99cb6711fd77306ba0a8a5c057d6368f949 100644
--- a/perl/lib/Nix/Config.pm.in
+++ b/perl/lib/Nix/Config.pm.in
@@ -33,7 +33,7 @@ sub readConfig {
         my $config = "$confDir/nix.conf";
         return unless -f $config;
 
-        open CONFIG, "<$config" or die "cannot open '$config'";
+        open CONFIG, "<$config" or die "cannot open ‘$config’";
         while (<CONFIG>) {
             /^\s*([\w\-\.]+)\s*=\s*(.*)$/ or next;
             $config{$1} = $2;
diff --git a/perl/lib/Nix/CopyClosure.pm b/perl/lib/Nix/CopyClosure.pm
index 902ee1a1bc9f047ef27d8d05e59e3e5cb296b6a4..affb3ea524aeec0338ffed311353a715ca8e698d 100644
--- a/perl/lib/Nix/CopyClosure.pm
+++ b/perl/lib/Nix/CopyClosure.pm
@@ -35,14 +35,14 @@ sub copyToOpen {
     my $missingSize = 0;
     $missingSize += (queryPathInfo($_, 1))[3] foreach @missing;
 
-    printf STDERR "copying %d missing paths (%.2f MiB) to '$sshHost'...\n",
+    printf STDERR "copying %d missing paths (%.2f MiB) to ‘$sshHost’...\n",
         scalar(@missing), $missingSize / (1024**2);
     return if $dryRun;
 
     # Send the "import paths" command.
     syswrite($to, pack("L<x4", 4)) or die;
     exportPaths(fileno($to), @missing);
-    readInt($from) == 1 or die "remote machine '$sshHost' failed to import closure\n";
+    readInt($from) == 1 or die "remote machine ‘$sshHost’ failed to import closure\n";
 }
 
 
diff --git a/perl/lib/Nix/Manifest.pm b/perl/lib/Nix/Manifest.pm
index 6438398e1766d4f61cffd18f99aaba55d4ed1384..0da3767612018c768721e243d9554f8fe87c60e6 100644
--- a/perl/lib/Nix/Manifest.pm
+++ b/perl/lib/Nix/Manifest.pm
@@ -60,10 +60,10 @@ sub readManifest_ {
     # Decompress the manifest if necessary.
     if ($manifest =~ /\.bz2$/) {
         open MANIFEST, "$Nix::Config::bzip2 -d < $manifest |"
-            or die "cannot decompress '$manifest': $!";
+            or die "cannot decompress ‘$manifest’: $!";
     } else {
         open MANIFEST, "<$manifest"
-            or die "cannot open '$manifest': $!";
+            or die "cannot open ‘$manifest’: $!";
     }
 
     my $inside = 0;
@@ -287,7 +287,7 @@ sub parseNARInfo {
         # FIXME: might be useful to support multiple signatures per .narinfo.
 
         if (!defined $sig) {
-            warn "NAR info file '$location' lacks a signature; ignoring\n";
+            warn "NAR info file ‘$location’ lacks a signature; ignoring\n";
             return undef;
         }
         my ($keyName, $sig64) = split ":", $sig;
@@ -295,7 +295,7 @@ sub parseNARInfo {
 
         my $publicKey = $Nix::Config::binaryCachePublicKeys{$keyName};
         if (!defined $publicKey) {
-            warn "NAR info file '$location' is signed by unknown key '$keyName'; ignoring\n";
+            warn "NAR info file ‘$location’ is signed by unknown key ‘$keyName’; ignoring\n";
             return undef;
         }
 
@@ -306,12 +306,12 @@ sub parseNARInfo {
                 [ map { "$Nix::Config::storeDir/$_" } @refs ]);
         };
         if ($@) {
-            warn "cannot compute fingerprint of '$location'; ignoring\n";
+            warn "cannot compute fingerprint of ‘$location’; ignoring\n";
             return undef;
         }
 
         if (!checkSignature($publicKey, decode_base64($sig64), $fingerprint)) {
-            warn "NAR info file '$location' has an incorrect signature; ignoring\n";
+            warn "NAR info file ‘$location’ has an incorrect signature; ignoring\n";
             return undef;
         }
 
diff --git a/perl/lib/Nix/SSH.pm b/perl/lib/Nix/SSH.pm
index 4b3d84b19383c083e4fa6b11c75ff2aa77a2609d..95393d8814502a76da3c6e728ea5b7124668ec30 100644
--- a/perl/lib/Nix/SSH.pm
+++ b/perl/lib/Nix/SSH.pm
@@ -84,7 +84,7 @@ sub connectToRemoteNix {
 
     $extraFlags ||= "";
 
-    # Start 'nix-store --serve' on the remote host.
+    # Start ‘nix-store --serve’ on the remote host.
     my ($from, $to);
     # FIXME: don't start a shell, start ssh directly.
     my $pid = open2($from, $to, "exec ssh -x -a $sshHost @globalSshOpts @{$sshOpts} nix-store --serve --write $extraFlags");
@@ -97,7 +97,7 @@ sub connectToRemoteNix {
         syswrite($to, pack("L<x4L<x4", $SERVE_MAGIC_1, $clientVersion)) or die;
         $magic = readInt($from);
     };
-    die "unable to connect to '$sshHost'\n" if $@;
+    die "unable to connect to ‘$sshHost’\n" if $@;
     die "did not get valid handshake from remote host\n" if $magic  != 0x5452eecb;
 
     my $serverVersion = readInt($from);
diff --git a/perl/lib/Nix/Utils.pm b/perl/lib/Nix/Utils.pm
index 44955a70698cfb365cf3f97cea34fabbca8245b9..392c45f2fffb670c0c098b42d7efb76cf13a8cfe 100644
--- a/perl/lib/Nix/Utils.pm
+++ b/perl/lib/Nix/Utils.pm
@@ -10,7 +10,7 @@ $urlRE = "(?: [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!
 
 sub checkURL {
     my ($url) = @_;
-    die "invalid URL '$url'\n" unless $url =~ /^ $urlRE $ /x;
+    die "invalid URL ‘$url’\n" unless $url =~ /^ $urlRE $ /x;
 }
 
 sub uniq {
@@ -26,7 +26,7 @@ sub uniq {
 
 sub writeFile {
     my ($fn, $s) = @_;
-    open TMP, ">$fn" or die "cannot create file '$fn': $!";
+    open TMP, ">$fn" or die "cannot create file ‘$fn’: $!";
     print TMP "$s" or die;
     close TMP or die;
 }
@@ -34,7 +34,7 @@ sub writeFile {
 sub readFile {
     local $/ = undef;
     my ($fn) = @_;
-    open TMP, "<$fn" or die "cannot open file '$fn': $!";
+    open TMP, "<$fn" or die "cannot open file ‘$fn’: $!";
     my $s = <TMP>;
     close TMP or die;
     return $s;
diff --git a/scripts/build-remote.pl.in b/scripts/build-remote.pl.in
index 62e517f06c07a0efff31f044d4111eb4b55d2656..b5fc629eb49951a65ea0baa488c246e59a10784d 100755
--- a/scripts/build-remote.pl.in
+++ b/scripts/build-remote.pl.in
@@ -209,7 +209,7 @@ REQ: while (1) {
         };
         last REQ unless $@;
         print STDERR "$@";
-        warn "unable to open SSH connection to '$hostName', trying other available machines...\n";
+        warn "unable to open SSH connection to ‘$hostName’, trying other available machines...\n";
         $from = undef;
         $to = undef;
         $machine->{enabled} = 0;
@@ -251,7 +251,7 @@ close UPLOADLOCK;
 
 
 # Perform the build.
-print STDERR "building '$drvPath' on '$hostName'\n";
+print STDERR "building ‘$drvPath’ on ‘$hostName’\n";
 writeInt(6, $to) or die; # == cmdBuildPaths
 writeStrings([$drvPath], $to);
 writeInt($maxSilentTime, $to);
@@ -259,7 +259,7 @@ writeInt($buildTimeout, $to);
 my $res = readInt($from);
 if ($res != 0) {
     my $msg = decode("utf-8", readString($from));
-    print STDERR "error: $msg on '$hostName'\n";
+    print STDERR "error: $msg on ‘$hostName’\n";
     exit $res;
 }
 
diff --git a/scripts/install-nix-from-closure.sh b/scripts/install-nix-from-closure.sh
index 2b1d1888bb5001bb1fc9622fe66de9b544478c1d..fd38a4528cd7b3ccb9defa492859630338c689b7 100644
--- a/scripts/install-nix-from-closure.sh
+++ b/scripts/install-nix-from-closure.sh
@@ -27,13 +27,13 @@ if ! [ -e $dest ]; then
     cmd="mkdir -m 0755 $dest && chown $USER $dest"
     echo "directory $dest does not exist; creating it by running '$cmd' using sudo" >&2
     if ! sudo sh -c "$cmd"; then
-        echo "$0: please manually run '$cmd' as root to create $dest" >&2
+        echo "$0: please manually run ‘$cmd’ as root to create $dest" >&2
         exit 1
     fi
 fi
 
 if ! [ -w $dest ]; then
-    echo "$0: directory $dest exists, but is not writable by you. This could indicate that another user has already performed a single-user installation of Nix on this system. If you wish to enable multi-user support see http://nixos.org/nix/manual/#ssec-multi-user. If you wish to continue with a single-user install for $USER please run 'chown -R $USER $dest' as root." >&2
+    echo "$0: directory $dest exists, but is not writable by you. This could indicate that another user has already performed a single-user installation of Nix on this system. If you wish to enable multi-user support see http://nixos.org/nix/manual/#ssec-multi-user. If you wish to continue with a single-user install for $USER please run ‘chown -R $USER $dest’ as root." >&2
     exit 1
 fi
 
diff --git a/scripts/nix-copy-closure.in b/scripts/nix-copy-closure.in
index 24912c8dbb075025fb7433dc9ca2bb7b6e7689d7..af1d30919263ca51109c02a64fc6f70a9dd4dfdb 100755
--- a/scripts/nix-copy-closure.in
+++ b/scripts/nix-copy-closure.in
@@ -38,7 +38,7 @@ while (@ARGV) {
         exec "man nix-copy-closure" or die;
     }
     elsif ($arg eq "--gzip" || $arg eq "--bzip2" || $arg eq "--xz") {
-        warn "$0: '$arg' is not implemented\n" if $arg ne "--gzip";
+        warn "$0: ‘$arg’ is not implemented\n" if $arg ne "--gzip";
         push @globalSshOpts, "-C";
     }
     elsif ($arg eq "--from") {
@@ -51,7 +51,7 @@ while (@ARGV) {
         $includeOutputs = 1;
     }
     elsif ($arg eq "--show-progress") {
-        warn "$0: '$arg' is not implemented\n";
+        warn "$0: ‘$arg’ is not implemented\n";
     }
     elsif ($arg eq "--dry-run") {
         $dryRun = 1;
@@ -93,7 +93,7 @@ else { # Copy FROM the remote machine.
 
     # Export the store paths on the remote machine and import them locally.
     if (scalar @missing > 0) {
-        print STDERR "copying ", scalar @missing, " missing paths from '$sshHost'...\n";
+        print STDERR "copying ", scalar @missing, " missing paths from ‘$sshHost’...\n";
         writeInt(5, $to); # == cmdExportPaths
         writeInt(0, $to); # obsolete
         writeStrings(\@missing, $to);
diff --git a/src/buildenv/buildenv.cc b/src/buildenv/buildenv.cc
index 885c5e16903997dc20be72a632c282bc8cccc3c8..f997096eddbb9f0b676eba257c826d4311916b50 100644
--- a/src/buildenv/buildenv.cc
+++ b/src/buildenv/buildenv.cc
@@ -12,7 +12,7 @@ static bool isDirectory (const Path & path)
 {
     struct stat st;
     if (stat(path.c_str(), &st) == -1)
-        throw SysError(format("getting status of '%1%'") % path);
+        throw SysError(format("getting status of ‘%1%’") % path);
     return S_ISDIR(st.st_mode);
 }
 
@@ -53,18 +53,18 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
                 } else if (S_ISLNK(dstSt.st_mode)) {
                     auto target = readLink(dstFile);
                     if (!isDirectory(target))
-                        throw Error(format("collision between '%1%' and non-directory '%2%'")
+                        throw Error(format("collision between ‘%1%’ and non-directory ‘%2%’")
                             % srcFile % target);
                     if (unlink(dstFile.c_str()) == -1)
-                        throw SysError(format("unlinking '%1%'") % dstFile);
+                        throw SysError(format("unlinking ‘%1%’") % dstFile);
                     if (mkdir(dstFile.c_str(), 0755) == -1)
-                        throw SysError(format("creating directory '%1%'"));
+                        throw SysError(format("creating directory ‘%1%’"));
                     createLinks(target, dstFile, priorities[dstFile]);
                     createLinks(srcFile, dstFile, priority);
                     continue;
                 }
             } else if (errno != ENOENT)
-                throw SysError(format("getting status of '%1%'") % dstFile);
+                throw SysError(format("getting status of ‘%1%’") % dstFile);
         } else {
             struct stat dstSt;
             auto res = lstat(dstFile.c_str(), &dstSt);
@@ -74,17 +74,17 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
                     auto prevPriority = priorities[dstFile];
                     if (prevPriority == priority)
                         throw Error(format(
-                                "collision between '%1%' and '%2%'; "
-                                "use 'nix-env --set-flag priority NUMBER PKGNAME' "
+                                "collision between ‘%1%’ and ‘%2%’; "
+                                "use ‘nix-env --set-flag priority NUMBER PKGNAME’ "
                                 "to change the priority of one of the conflicting packages"
                                 ) % srcFile % target);
                     if (prevPriority < priority)
                         continue;
                     if (unlink(dstFile.c_str()) == -1)
-                        throw SysError(format("unlinking '%1%'") % dstFile);
+                        throw SysError(format("unlinking ‘%1%’") % dstFile);
                 }
             } else if (errno != ENOENT)
-                throw SysError(format("getting status of '%1%'") % dstFile);
+                throw SysError(format("getting status of ‘%1%’") % dstFile);
         }
         createSymlink(srcFile, dstFile);
         priorities[dstFile] = priority;
@@ -112,7 +112,7 @@ static void addPkg(const Path & pkgDir, int priority)
         if (!fd) {
             if (errno == ENOENT)
                 return;
-            throw SysError(format("opening '%1%'") % propagatedFN);
+            throw SysError(format("opening ‘%1%’") % propagatedFN);
         }
         propagated = readLine(fd.get());
     }
diff --git a/src/download-via-ssh/download-via-ssh.cc b/src/download-via-ssh/download-via-ssh.cc
index 5c4756372afa61c9a3784a615fbbe238320586b6..ff28a60ff4b0e67003c934d4bef4068cf9a8cdc7 100644
--- a/src/download-via-ssh/download-via-ssh.cc
+++ b/src/download-via-ssh/download-via-ssh.cc
@@ -85,7 +85,7 @@ static void query(std::pair<FdSink, FdSource> & pipes)
                 std::cout << readLongLong(pipes.second) << std::endl;
             }
         } else
-            throw Error(format("unknown substituter query '%1%'") % cmd);
+            throw Error(format("unknown substituter query ‘%1%’") % cmd);
         std::cout << std::endl;
     }
 }
@@ -132,10 +132,10 @@ int main(int argc, char * * argv)
                 throw UsageError("download-via-ssh: --substitute takes exactly two arguments");
             Path storePath = argv[2];
             Path destPath = argv[3];
-            printError(format("downloading '%1%' via SSH from '%2%'...") % storePath % host);
+            printError(format("downloading ‘%1%’ via SSH from ‘%2%’...") % storePath % host);
             substitute(pipes, storePath, destPath);
         }
         else
-            throw UsageError(format("download-via-ssh: unknown command '%1%'") % arg);
+            throw UsageError(format("download-via-ssh: unknown command ‘%1%’") % arg);
     });
 }
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc
index b0f80db32a884eee2cced5f753b769c77956cd34..55379f94b1895f0d82c755b393a5a927334acfb3 100644
--- a/src/libexpr/attr-path.cc
+++ b/src/libexpr/attr-path.cc
@@ -19,7 +19,7 @@ static Strings parseAttrPath(const string & s)
             ++i;
             while (1) {
                 if (i == s.end())
-                    throw Error(format("missing closing quote in selection path '%1%'") % s);
+                    throw Error(format("missing closing quote in selection path ‘%1%’") % s);
                 if (*i == '"') break;
                 cur.push_back(*i++);
             }
@@ -38,7 +38,7 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
     Strings tokens = parseAttrPath(attrPath);
 
     Error attrError =
-        Error(format("attribute selection path '%1%' does not match expression") % attrPath);
+        Error(format("attribute selection path ‘%1%’ does not match expression") % attrPath);
 
     Value * v = &vIn;
 
@@ -62,15 +62,15 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
 
             if (v->type != tAttrs)
                 throw TypeError(
-                    format("the expression selected by the selection path '%1%' should be a set but is %2%")
+                    format("the expression selected by the selection path ‘%1%’ should be a set but is %2%")
                     % attrPath % showType(*v));
 
             if (attr.empty())
-                throw Error(format("empty attribute name in selection path '%1%'") % attrPath);
+                throw Error(format("empty attribute name in selection path ‘%1%’") % attrPath);
 
             Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
             if (a == v->attrs->end())
-                throw Error(format("attribute '%1%' in selection path '%2%' not found") % attr % attrPath);
+                throw Error(format("attribute ‘%1%’ in selection path ‘%2%’ not found") % attr % attrPath);
             v = &*a->value;
         }
 
@@ -78,11 +78,11 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
 
             if (!v->isList())
                 throw TypeError(
-                    format("the expression selected by the selection path '%1%' should be a list but is %2%")
+                    format("the expression selected by the selection path ‘%1%’ should be a list but is %2%")
                     % attrPath % showType(*v));
 
             if (attrIndex >= v->listSize())
-                throw Error(format("list index %1% in selection path '%2%' is out of range") % attrIndex % attrPath);
+                throw Error(format("list index %1% in selection path ‘%2%’ is out of range") % attrIndex % attrPath);
 
             v = v->listElems()[attrIndex];
         }
diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc
index 6b31961d345b13bf03804fa643a3bd841d9ce2d1..06d6ed87df9442e4418de185cc11897d3c79913e 100644
--- a/src/libexpr/common-opts.cc
+++ b/src/libexpr/common-opts.cc
@@ -13,7 +13,7 @@ bool parseAutoArgs(Strings::iterator & i,
     string arg = *i;
     if (arg != "--arg" && arg != "--argstr") return false;
 
-    UsageError error(format("'%1%' requires two arguments") % arg);
+    UsageError error(format("‘%1%’ requires two arguments") % arg);
 
     if (++i == argsEnd) throw error;
     string name = *i;
@@ -46,7 +46,7 @@ bool parseSearchPathArg(Strings::iterator & i,
     const Strings::iterator & argsEnd, Strings & searchPath)
 {
     if (*i != "-I") return false;
-    if (++i == argsEnd) throw UsageError("'-I' requires an argument");
+    if (++i == argsEnd) throw UsageError("‘-I’ requires an argument");
     searchPath.push_back(*i);
     return true;
 }
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 0b8f07fbfa9cc237b5572194c6092d0df6dcbfd1..64f3874db6148aaa9727761eb6556a507a9262d0 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -330,7 +330,7 @@ Path EvalState::checkSourcePath(const Path & path_)
     if (!restricted) return path_;
 
     /* Resolve symlinks. */
-    debug(format("checking access to '%s'") % path_);
+    debug(format("checking access to ‘%s’") % path_);
     Path path = canonPath(path_, true);
 
     for (auto & i : searchPath) {
@@ -352,7 +352,7 @@ Path EvalState::checkSourcePath(const Path & path_)
         return path;
 #endif
 
-    throw RestrictedPathError(format("access to path '%1%' is forbidden in restricted mode") % path_);
+    throw RestrictedPathError(format("access to path ‘%1%’ is forbidden in restricted mode") % path_);
 }
 
 
@@ -505,7 +505,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
             return j->value;
         }
         if (!env->prevWith)
-            throwUndefinedVarError("undefined variable '%1%' at %2%", var.name, var.pos);
+            throwUndefinedVarError("undefined variable ‘%1%’ at %2%", var.name, var.pos);
         for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
     }
 }
@@ -644,12 +644,12 @@ void EvalState::evalFile(const Path & path, Value & v)
         return;
     }
 
-    Activity act(*logger, lvlTalkative, format("evaluating file '%1%'") % path2);
+    Activity act(*logger, lvlTalkative, format("evaluating file ‘%1%’") % path2);
     Expr * e = parseExprFromFile(checkSourcePath(path2));
     try {
         eval(e, v);
     } catch (Error & e) {
-        addErrorPrefix(e, "while evaluating the file '%1%':\n", path2);
+        addErrorPrefix(e, "while evaluating the file ‘%1%’:\n", path2);
         throw;
     }
 
@@ -799,7 +799,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
         Symbol nameSym = state.symbols.create(nameVal.string.s);
         Bindings::iterator j = v.attrs->find(nameSym);
         if (j != v.attrs->end())
-            throwEvalError("dynamic attribute '%1%' at %2% already defined at %3%", nameSym, i.pos, *j->pos);
+            throwEvalError("dynamic attribute ‘%1%’ at %2% already defined at %3%", nameSym, i.pos, *j->pos);
 
         i.valueExpr->setName(nameSym);
         /* Keep sorted order so find can catch duplicates */
@@ -887,7 +887,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
             } else {
                 state.forceAttrs(*vAttrs, pos);
                 if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
-                    throwEvalError("attribute '%1%' missing, at %2%", name, pos);
+                    throwEvalError("attribute ‘%1%’ missing, at %2%", name, pos);
             }
             vAttrs = j->value;
             pos2 = j->pos;
@@ -898,7 +898,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
 
     } catch (Error & e) {
         if (pos2 && pos2->file != state.sDerivationNix)
-            addErrorPrefix(e, "while evaluating the attribute '%1%' at %2%:\n",
+            addErrorPrefix(e, "while evaluating the attribute ‘%1%’ at %2%:\n",
                 showAttrPath(state, env, attrPath), *pos2);
         throw;
     }
@@ -1040,7 +1040,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
         for (auto & i : lambda.formals->formals) {
             Bindings::iterator j = arg.attrs->find(i.name);
             if (j == arg.attrs->end()) {
-                if (!i.def) throwTypeError("%1% called without required argument '%2%', at %3%",
+                if (!i.def) throwTypeError("%1% called without required argument ‘%2%’, at %3%",
                     lambda, i.name, pos);
                 env2.values[displ++] = i.def->maybeThunk(*this, env2);
             } else {
@@ -1056,7 +1056,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
                user. */
             for (auto & i : *arg.attrs)
                 if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end())
-                    throwTypeError("%1% called with unexpected argument '%2%', at %3%", lambda, i.name, pos);
+                    throwTypeError("%1% called with unexpected argument ‘%2%’, at %3%", lambda, i.name, pos);
             abort(); // can't happen
         }
     }
@@ -1114,7 +1114,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
         if (j != args.end())
             actualArgs->attrs->push_back(*j);
         else if (!i.def)
-            throwTypeError("cannot auto-call a function that has an argument without a default value ('%1%')", i.name);
+            throwTypeError("cannot auto-call a function that has an argument without a default value (‘%1%’)", i.name);
     }
 
     actualArgs->attrs->sort();
@@ -1343,7 +1343,7 @@ void EvalState::forceValueDeep(Value & v)
                 try {
                     recurse(*i.value);
                 } catch (Error & e) {
-                    addErrorPrefix(e, "while evaluating the attribute '%1%' at %2%:\n", i.name, *i.pos);
+                    addErrorPrefix(e, "while evaluating the attribute ‘%1%’ at %2%:\n", i.name, *i.pos);
                     throw;
                 }
         }
@@ -1435,10 +1435,10 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos)
     string s = forceString(v, pos);
     if (v.string.context) {
         if (pos)
-            throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%'), at %3%",
+            throwEvalError("the string ‘%1%’ is not allowed to refer to a store path (such as ‘%2%’), at %3%",
                 v.string.s, v.string.context[0], pos);
         else
-            throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')",
+            throwEvalError("the string ‘%1%’ is not allowed to refer to a store path (such as ‘%2%’)",
                 v.string.s, v.string.context[0]);
     }
     return s;
@@ -1520,7 +1520,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
 string EvalState::copyPathToStore(PathSet & context, const Path & path)
 {
     if (nix::isDerivation(path))
-        throwEvalError("file names are not allowed to end in '%1%'", drvExtension);
+        throwEvalError("file names are not allowed to end in ‘%1%’", drvExtension);
 
     Path dstPath;
     if (srcToStore[path] != "")
@@ -1530,7 +1530,7 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path)
             ? store->computeStorePathForPath(checkSourcePath(path)).first
             : store->addToStore(baseNameOf(path), checkSourcePath(path), true, htSHA256, defaultPathFilter, repair);
         srcToStore[path] = dstPath;
-        printMsg(lvlChatty, format("copied source '%1%' -> '%2%'")
+        printMsg(lvlChatty, format("copied source ‘%1%’ -> ‘%2%’")
             % path % dstPath);
     }
 
@@ -1543,7 +1543,7 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
 {
     string path = coerceToString(pos, v, context, false, false);
     if (path == "" || path[0] != '/')
-        throwEvalError("string '%1%' doesn't represent an absolute path, at %2%", path, pos);
+        throwEvalError("string ‘%1%’ doesn't represent an absolute path, at %2%", path, pos);
     return path;
 }
 
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 810f35d5ac7eeae6724349e81f224fe4e7d62dc7..195cb0db3acc7afb4c31112040b2b76672f00f31 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -32,7 +32,7 @@ struct PrimOp
 struct Env
 {
     Env * up;
-    unsigned short size; // used by 'valueSize'
+    unsigned short size; // used by ‘valueSize’
     unsigned short prevWith:15; // nr of levels up to next `with' environment
     unsigned short haveWithAttrs:1;
     Value * values[0];
diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc
index 55c9105439998e0a5618e448c0eabca7c450a561..dc5def911ca09144d1aa68c1b079eb5b858530c5 100644
--- a/src/libexpr/get-drvs.cc
+++ b/src/libexpr/get-drvs.cc
@@ -33,7 +33,7 @@ string DrvInfo::queryOutPath()
 DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
 {
     if (outputs.empty()) {
-        /* Get the 'outputs' list. */
+        /* Get the ‘outputs’ list. */
         Bindings::iterator i;
         if (attrs && (i = attrs->find(state->sOutputs)) != attrs->end()) {
             state->forceList(*i->value, *i->pos);
@@ -46,7 +46,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
                 if (out == attrs->end()) continue; // FIXME: throw error?
                 state->forceAttrs(*out->value);
 
-                /* And evaluate its 'outPath' attribute. */
+                /* And evaluate its ‘outPath’ attribute. */
                 Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
                 if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
                 PathSet context;
@@ -61,7 +61,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
     /* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */
     const Value * outTI = queryMeta("outputsToInstall");
     if (!outTI) return outputs;
-    const auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'");
+    const auto errMsg = Error("this derivation has bad ‘meta.outputsToInstall’");
         /* ^ this shows during `nix-env -i` right under the bad derivation */
     if (!outTI->isList()) throw errMsg;
     Outputs result;
@@ -290,7 +290,7 @@ static void getDerivations(EvalState & state, Value & vIn,
             attrs.insert(std::pair<string, Symbol>(i.name, i.name));
 
         for (auto & i : attrs) {
-            Activity act(*logger, lvlDebug, format("evaluating attribute '%1%'") % i.first);
+            Activity act(*logger, lvlDebug, format("evaluating attribute ‘%1%’") % i.first);
             string pathPrefix2 = addToPath(pathPrefix, i.first);
             Value & v2(*v.attrs->find(i.second)->value);
             if (combineChannels)
diff --git a/src/libexpr/json-to-value.cc b/src/libexpr/json-to-value.cc
index b8f2542a3717e31bb0e026cf29bbd5b22fff1129..f671802bcc247ae83fdaf3a1bf2cb378b5559bba 100644
--- a/src/libexpr/json-to-value.cc
+++ b/src/libexpr/json-to-value.cc
@@ -58,7 +58,7 @@ static void parseJSON(EvalState & state, const char * & s, Value & v)
             values.push_back(v2);
             skipWhitespace(s);
             if (*s == ']') break;
-            if (*s != ',') throw JSONParseError("expected ',' or ']' after JSON array element");
+            if (*s != ',') throw JSONParseError("expected ‘,’ or ‘]’ after JSON array element");
             s++;
         }
         s++;
@@ -75,14 +75,14 @@ static void parseJSON(EvalState & state, const char * & s, Value & v)
             if (attrs.empty() && *s == '}') break;
             string name = parseJSONString(s);
             skipWhitespace(s);
-            if (*s != ':') throw JSONParseError("expected ':' in JSON object");
+            if (*s != ':') throw JSONParseError("expected ‘:’ in JSON object");
             s++;
             Value * v2 = state.allocValue();
             parseJSON(state, s, *v2);
             attrs[state.symbols.create(name)] = v2;
             skipWhitespace(s);
             if (*s == '}') break;
-            if (*s != ',') throw JSONParseError("expected ',' or '}' after JSON member");
+            if (*s != ',') throw JSONParseError("expected ‘,’ or ‘}’ after JSON member");
             s++;
         }
         state.mkAttrs(v, attrs.size());
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index a4bc2ea0319f512ef7514296fa4cd46dd8f314e5..3ac7ce723cb38e65bbfd5527739394f325193488 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -124,13 +124,13 @@ or          { return OR_KW; }
 {INT}       { errno = 0;
               yylval->n = strtol(yytext, 0, 10);
               if (errno != 0)
-                  throw ParseError(format("invalid integer '%1%'") % yytext);
+                  throw ParseError(format("invalid integer ‘%1%’") % yytext);
               return INT;
             }
 {FLOAT}     { errno = 0;
               yylval->nf = strtod(yytext, 0);
               if (errno != 0)
-                  throw ParseError(format("invalid float '%1%'") % yytext);
+                  throw ParseError(format("invalid float ‘%1%’") % yytext);
               return FLOAT;
             }
 
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 7b0a127cd41c28aac8124d474b57715fa7f9223d..b2c9f0528ca98a648ee9b91cbca72e64b4b0849a 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -267,7 +267,7 @@ void ExprVar::bindVars(const StaticEnv & env)
     /* Otherwise, the variable must be obtained from the nearest
        enclosing `with'.  If there is no `with', then we can issue an
        "undefined variable" error now. */
-    if (withLevel == -1) throw UndefinedVarError(format("undefined variable '%1%' at %2%") % name % pos);
+    if (withLevel == -1) throw UndefinedVarError(format("undefined variable ‘%1%’ at %2%") % name % pos);
 
     fromWith = true;
     this->level = withLevel;
@@ -419,7 +419,7 @@ void ExprLambda::setName(Symbol & name)
 
 string ExprLambda::showNamePos() const
 {
-    return (format("%1% at %2%") % (name.set() ? "'" + (string) name + "'" : "anonymous function") % pos).str();
+    return (format("%1% at %2%") % (name.set() ? "‘" + (string) name + "’" : "anonymous function") % pos).str();
 }
 
 
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index 30be79bb57a6504eb5f155332041812db1dbecb5..d2ca09b3a5bbec5a6f113f69338dc7bd5f822061 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -235,7 +235,7 @@ struct ExprLambda : Expr
         : pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body)
     {
         if (!arg.empty() && formals && formals->argNames.find(arg) != formals->argNames.end())
-            throw ParseError(format("duplicate formal function argument '%1%' at %2%")
+            throw ParseError(format("duplicate formal function argument ‘%1%’ at %2%")
                 % arg % pos);
     };
     void setName(Symbol & name);
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 5d685f8fa493c237d9d982ecedc5daf893a6f0af..d07eedddaf6becb98b9353bf08c4ed5acf7a57fa 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -65,14 +65,14 @@ namespace nix {
 
 static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prevPos)
 {
-    throw ParseError(format("attribute '%1%' at %2% already defined at %3%")
+    throw ParseError(format("attribute ‘%1%’ at %2% already defined at %3%")
         % showAttrPath(attrPath) % pos % prevPos);
 }
 
 
 static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
 {
-    throw ParseError(format("attribute '%1%' at %2% already defined at %3%")
+    throw ParseError(format("attribute ‘%1%’ at %2% already defined at %3%")
         % attr % pos % prevPos);
 }
 
@@ -121,7 +121,7 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
 static void addFormal(const Pos & pos, Formals * formals, const Formal & formal)
 {
     if (formals->argNames.find(formal.name) != formals->argNames.end())
-        throw ParseError(format("duplicate formal function argument '%1%' at %2%")
+        throw ParseError(format("duplicate formal function argument ‘%1%’ at %2%")
             % formal.name % pos);
     formals->formals.push_front(formal);
     formals->argNames.insert(formal.name);
@@ -356,7 +356,7 @@ expr_select
   | expr_simple '.' attrpath OR_KW expr_select
     { $$ = new ExprSelect(CUR_POS, $1, *$3, $5); }
   | /* Backwards compatibility: because Nixpkgs has a rarely used
-       function named 'or', allow stuff like 'map or [...]'. */
+       function named ‘or’, allow stuff like ‘map or [...]’. */
     expr_simple OR_KW
     { $$ = new ExprApp(CUR_POS, $1, new ExprVar(CUR_POS, data->symbols.create("or"))); }
   | expr_simple { $$ = $1; }
@@ -564,7 +564,7 @@ Path resolveExprPath(Path path)
     struct stat st;
     while (true) {
         if (lstat(path.c_str(), &st))
-            throw SysError(format("getting status of '%1%'") % path);
+            throw SysError(format("getting status of ‘%1%’") % path);
         if (!S_ISLNK(st.st_mode)) break;
         path = absPath(readLink(path), dirOf(path));
     }
@@ -642,7 +642,7 @@ Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos
         if (pathExists(res)) return canonPath(res);
     }
     format f = format(
-        "file '%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)"
+        "file ‘%1%’ was not found in the Nix search path (add it using $NIX_PATH or -I)"
         + string(pos ? ", at %2%" : ""));
     f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
     throw ThrownError(f % path % pos);
@@ -664,7 +664,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
             else
                 res = { true, getDownloader()->downloadCached(store, elem.second, true) };
         } catch (DownloadError & e) {
-            printError(format("warning: Nix search path entry '%1%' cannot be downloaded, ignoring") % elem.second);
+            printError(format("warning: Nix search path entry ‘%1%’ cannot be downloaded, ignoring") % elem.second);
             res = { false, "" };
         }
     } else {
@@ -672,12 +672,12 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
         if (pathExists(path))
             res = { true, path };
         else {
-            printError(format("warning: Nix search path entry '%1%' does not exist, ignoring") % elem.second);
+            printError(format("warning: Nix search path entry ‘%1%’ does not exist, ignoring") % elem.second);
             res = { false, "" };
         }
     }
 
-    debug(format("resolved search path element '%s' to '%s'") % elem.second % res.second);
+    debug(format("resolved search path element ‘%s’ to ‘%s’") % elem.second % res.second);
 
     searchPathResolved[elem.second] = res;
     return res;
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 02638fea7cebe6c15b428f37bc2028bf624dec7f..4398cc951da2c3d88dfbe92af5597deaab93e5ce 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -30,7 +30,7 @@ namespace nix {
  *************************************************************/
 
 
-/* Decode a context string '!<name>!<path>' into a pair <path,
+/* Decode a context string ‘!<name>!<path>’ into a pair <path,
    name>. */
 std::pair<string, string> decodeContext(const string & s)
 {
@@ -43,7 +43,7 @@ std::pair<string, string> decodeContext(const string & s)
 
 
 InvalidPathError::InvalidPathError(const Path & path) :
-    EvalError(format("path '%1%' is not valid") % path), path(path) {}
+    EvalError(format("path ‘%1%’ is not valid") % path), path(path) {}
 
 void EvalState::realiseContext(const PathSet & context)
 {
@@ -77,7 +77,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
     try {
         state.realiseContext(context);
     } catch (InvalidPathError & e) {
-        throw EvalError(format("cannot import '%1%', since path '%2%' is not valid, at %3%")
+        throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%")
             % path % e.path % pos);
     }
 
@@ -124,7 +124,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
                 env->values[displ++] = attr.value;
             }
 
-            Activity act(*logger, lvlTalkative, format("evaluating file '%1%'") % path);
+            Activity act(*logger, lvlTalkative, format("evaluating file ‘%1%’") % path);
             Expr * e = state.parseExprFromFile(resolveExprPath(path), staticEnv);
 
             e->eval(state, *env, v);
@@ -146,7 +146,7 @@ static void prim_importNative(EvalState & state, const Pos & pos, Value * * args
     try {
         state.realiseContext(context);
     } catch (InvalidPathError & e) {
-        throw EvalError(format("cannot import '%1%', since path '%2%' is not valid, at %3%")
+        throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%")
             % path % e.path % pos);
     }
 
@@ -156,16 +156,16 @@ static void prim_importNative(EvalState & state, const Pos & pos, Value * * args
 
     void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
     if (!handle)
-        throw EvalError(format("could not open '%1%': %2%") % path % dlerror());
+        throw EvalError(format("could not open ‘%1%’: %2%") % path % dlerror());
 
     dlerror();
     ValueInitializer func = (ValueInitializer) dlsym(handle, sym.c_str());
     if(!func) {
         char *message = dlerror();
         if (message)
-            throw EvalError(format("could not load symbol '%1%' from '%2%': %3%") % sym % path % message);
+            throw EvalError(format("could not load symbol ‘%1%’ from ‘%2%’: %3%") % sym % path % message);
         else
-            throw EvalError(format("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected")
+            throw EvalError(format("symbol ‘%1%’ from ‘%2%’ resolved to NULL when a function pointer was expected")
                     % sym % path);
     }
 
@@ -292,7 +292,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
     Bindings::iterator startSet =
         args[0]->attrs->find(state.symbols.create("startSet"));
     if (startSet == args[0]->attrs->end())
-        throw EvalError(format("attribute 'startSet' required, at %1%") % pos);
+        throw EvalError(format("attribute ‘startSet’ required, at %1%") % pos);
     state.forceList(*startSet->value, pos);
 
     ValueList workSet;
@@ -303,7 +303,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
     Bindings::iterator op =
         args[0]->attrs->find(state.symbols.create("operator"));
     if (op == args[0]->attrs->end())
-        throw EvalError(format("attribute 'operator' required, at %1%") % pos);
+        throw EvalError(format("attribute ‘operator’ required, at %1%") % pos);
     state.forceValue(*op->value);
 
     /* Construct the closure by applying the operator to element of
@@ -322,7 +322,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
         Bindings::iterator key =
             e->attrs->find(state.symbols.create("key"));
         if (key == e->attrs->end())
-            throw EvalError(format("attribute 'key' required, at %1%") % pos);
+            throw EvalError(format("attribute ‘key’ required, at %1%") % pos);
         state.forceValue(*key->value);
 
         if (doneKeys.find(key->value) != doneKeys.end()) continue;
@@ -353,7 +353,7 @@ static void prim_abort(EvalState & state, const Pos & pos, Value * * args, Value
 {
     PathSet context;
     string s = state.coerceToString(pos, *args[0], context);
-    throw Abort(format("evaluation aborted with the following error message: '%1%'") % s);
+    throw Abort(format("evaluation aborted with the following error message: ‘%1%’") % s);
 }
 
 
@@ -464,13 +464,13 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
     /* Figure out the name first (for stack backtraces). */
     Bindings::iterator attr = args[0]->attrs->find(state.sName);
     if (attr == args[0]->attrs->end())
-        throw EvalError(format("required attribute 'name' missing, at %1%") % pos);
+        throw EvalError(format("required attribute ‘name’ missing, at %1%") % pos);
     string drvName;
     Pos & posDrvName(*attr->pos);
     try {
         drvName = state.forceStringNoCtx(*attr->value, pos);
     } catch (Error & e) {
-        e.addPrefix(format("while evaluating the derivation attribute 'name' at %1%:\n") % posDrvName);
+        e.addPrefix(format("while evaluating the derivation attribute ‘name’ at %1%:\n") % posDrvName);
         throw;
     }
 
@@ -494,7 +494,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
     for (auto & i : *args[0]->attrs) {
         if (i.name == state.sIgnoreNulls) continue;
         string key = i.name;
-        Activity act(*logger, lvlVomit, format("processing attribute '%1%'") % key);
+        Activity act(*logger, lvlVomit, format("processing attribute ‘%1%’") % key);
 
         try {
 
@@ -522,28 +522,28 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
                 else if (i.name == state.sSystem) drv.platform = s;
                 else if (i.name == state.sName) {
                     drvName = s;
-                    printMsg(lvlVomit, format("derivation name is '%1%'") % drvName);
+                    printMsg(lvlVomit, format("derivation name is ‘%1%’") % drvName);
                 }
                 else if (key == "outputHash") outputHash = s;
                 else if (key == "outputHashAlgo") outputHashAlgo = s;
                 else if (key == "outputHashMode") {
                     if (s == "recursive") outputHashRecursive = true;
                     else if (s == "flat") outputHashRecursive = false;
-                    else throw EvalError(format("invalid value '%1%' for 'outputHashMode' attribute, at %2%") % s % posDrvName);
+                    else throw EvalError(format("invalid value ‘%1%’ for ‘outputHashMode’ attribute, at %2%") % s % posDrvName);
                 }
                 else if (key == "outputs") {
                     Strings tmp = tokenizeString<Strings>(s);
                     outputs.clear();
                     for (auto & j : tmp) {
                         if (outputs.find(j) != outputs.end())
-                            throw EvalError(format("duplicate derivation output '%1%', at %2%") % j % posDrvName);
+                            throw EvalError(format("duplicate derivation output ‘%1%’, at %2%") % j % posDrvName);
                         /* !!! Check whether j is a valid attribute
                            name. */
-                        /* Derivations cannot be named 'drv', because
-                           then we'd have an attribute 'drvPath' in
+                        /* Derivations cannot be named ‘drv’, because
+                           then we'd have an attribute ‘drvPath’ in
                            the resulting set. */
                         if (j == "drv")
-                            throw EvalError(format("invalid derivation output name 'drv', at %1%") % posDrvName);
+                            throw EvalError(format("invalid derivation output name ‘drv’, at %1%") % posDrvName);
                         outputs.insert(j);
                     }
                     if (outputs.empty())
@@ -552,7 +552,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
             }
 
         } catch (Error & e) {
-            e.addPrefix(format("while evaluating the attribute '%1%' of the derivation '%2%' at %3%:\n")
+            e.addPrefix(format("while evaluating the attribute ‘%1%’ of the derivation ‘%2%’ at %3%:\n")
                 % key % drvName % posDrvName);
             throw;
         }
@@ -585,14 +585,14 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
         else if (path.at(0) == '~')
             drv.inputSrcs.insert(string(path, 1));
 
-        /* Handle derivation outputs of the form '!<name>!<path>'. */
+        /* Handle derivation outputs of the form ‘!<name>!<path>’. */
         else if (path.at(0) == '!') {
             std::pair<string, string> ctx = decodeContext(path);
             drv.inputDrvs[ctx.first].insert(ctx.second);
         }
 
         /* Handle derivation contexts returned by
-           'builtins.storePath'. */
+           ‘builtins.storePath’. */
         else if (isDerivation(path))
             drv.inputDrvs[path] = state.store->queryDerivationOutputNames(path);
 
@@ -603,14 +603,14 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
 
     /* Do we have all required attributes? */
     if (drv.builder == "")
-        throw EvalError(format("required attribute 'builder' missing, at %1%") % posDrvName);
+        throw EvalError(format("required attribute ‘builder’ missing, at %1%") % posDrvName);
     if (drv.platform == "")
-        throw EvalError(format("required attribute 'system' missing, at %1%") % posDrvName);
+        throw EvalError(format("required attribute ‘system’ missing, at %1%") % posDrvName);
 
     /* Check whether the derivation name is valid. */
     checkStoreName(drvName);
     if (isDerivation(drvName))
-        throw EvalError(format("derivation names are not allowed to end in '%1%', at %2%")
+        throw EvalError(format("derivation names are not allowed to end in ‘%1%’, at %2%")
             % drvExtension % posDrvName);
 
     if (outputHash != "") {
@@ -620,7 +620,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
 
         HashType ht = parseHashType(outputHashAlgo);
         if (ht == htUnknown)
-            throw EvalError(format("unknown hash algorithm '%1%', at %2%") % outputHashAlgo % posDrvName);
+            throw EvalError(format("unknown hash algorithm ‘%1%’, at %2%") % outputHashAlgo % posDrvName);
         Hash h = parseHash16or32(ht, outputHash);
         outputHash = printHash(h);
         if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
@@ -656,7 +656,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
     /* Write the resulting term into the Nix store directory. */
     Path drvPath = writeDerivation(state.store, drv, drvName, state.repair);
 
-    printMsg(lvlChatty, format("instantiated '%1%' -> '%2%'")
+    printMsg(lvlChatty, format("instantiated ‘%1%’ -> ‘%2%’")
         % drvName % drvPath);
 
     /* Optimisation, but required in read-only mode! because in that
@@ -676,11 +676,11 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
 
 /* Return a placeholder string for the specified output that will be
    substituted by the corresponding output path at build time. For
-   example, 'placeholder "out"' returns the string
+   example, ‘placeholder "out"’ returns the string
    /1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9. At build
    time, any occurence of this string in an derivation attribute will
    be replaced with the concrete path in the Nix store of the output
-   'out'. */
+   ‘out’. */
 static void prim_placeholder(EvalState & state, const Pos & pos, Value * * args, Value & v)
 {
     mkString(v, hashPlaceholder(state.forceStringNoCtx(*args[0], pos)));
@@ -713,12 +713,12 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V
 {
     PathSet context;
     Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context));
-    /* Resolve symlinks in 'path', unless 'path' itself is a symlink
+    /* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
        directly in the store.  The latter condition is necessary so
        e.g. nix-push does the right thing. */
     if (!state.store->isStorePath(path)) path = canonPath(path, true);
     if (!state.store->isInStore(path))
-        throw EvalError(format("path '%1%' is not in the Nix store, at %2%") % path % pos);
+        throw EvalError(format("path ‘%1%’ is not in the Nix store, at %2%") % path % pos);
     Path path2 = state.store->toStorePath(path);
     if (!settings.readOnlyMode)
         state.store->ensurePath(path2);
@@ -732,12 +732,12 @@ static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args,
     PathSet context;
     Path path = state.coerceToPath(pos, *args[0], context);
     if (!context.empty())
-        throw EvalError(format("string '%1%' cannot refer to other paths, at %2%") % path % pos);
+        throw EvalError(format("string ‘%1%’ cannot refer to other paths, at %2%") % path % pos);
     try {
         mkBool(v, pathExists(state.checkSourcePath(path)));
     } catch (SysError & e) {
         /* Don't give away info from errors while canonicalising
-           'path' in restricted mode. */
+           ‘path’ in restricted mode. */
         mkBool(v, false);
     } catch (RestrictedPathError & e) {
         mkBool(v, false);
@@ -773,18 +773,18 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va
     try {
         state.realiseContext(context);
     } catch (InvalidPathError & e) {
-        throw EvalError(format("cannot read '%1%', since path '%2%' is not valid, at %3%")
+        throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%")
             % path % e.path % pos);
     }
     string s = readFile(state.checkSourcePath(path));
     if (s.find((char) 0) != string::npos)
-        throw Error(format("the contents of the file '%1%' cannot be represented as a Nix string") % path);
+        throw Error(format("the contents of the file ‘%1%’ cannot be represented as a Nix string") % path);
     mkString(v, s.c_str(), context);
 }
 
 
 /* Find a file in the Nix search path. Used to implement <x> paths,
-   which are desugared to 'findFile __nixPath "x"'. */
+   which are desugared to ‘findFile __nixPath "x"’. */
 static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
 {
     state.forceList(*args[0], pos);
@@ -802,7 +802,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
 
         i = v2.attrs->find(state.symbols.create("path"));
         if (i == v2.attrs->end())
-            throw EvalError(format("attribute 'path' missing, at %1%") % pos);
+            throw EvalError(format("attribute ‘path’ missing, at %1%") % pos);
 
         PathSet context;
         string path = state.coerceToString(pos, *i->value, context, false, false);
@@ -810,7 +810,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
         try {
             state.realiseContext(context);
         } catch (InvalidPathError & e) {
-            throw EvalError(format("cannot find '%1%', since path '%2%' is not valid, at %3%")
+            throw EvalError(format("cannot find ‘%1%’, since path ‘%2%’ is not valid, at %3%")
                 % path % e.path % pos);
         }
 
@@ -830,7 +830,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val
     try {
         state.realiseContext(ctx);
     } catch (InvalidPathError & e) {
-        throw EvalError(format("cannot read '%1%', since path '%2%' is not valid, at %3%")
+        throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%")
             % path % e.path % pos);
     }
 
@@ -904,7 +904,7 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
         if (isDerivation(path)) {
             /* See prim_unsafeDiscardOutputDependency. */
             if (path.at(0) != '~')
-                throw EvalError(format("in 'toFile': the file '%1%' cannot refer to derivation outputs, at %2%") % name % pos);
+                throw EvalError(format("in ‘toFile’: the file ‘%1%’ cannot refer to derivation outputs, at %2%") % name % pos);
             path = string(path, 1);
         }
         refs.insert(path);
@@ -937,7 +937,7 @@ struct FilterFromExpr : PathFilter
     {
         struct stat st;
         if (lstat(path.c_str(), &st))
-            throw SysError(format("getting attributes of path '%1%'") % path);
+            throw SysError(format("getting attributes of path ‘%1%’") % path);
 
         /* Call the filter function.  The first argument is the path,
            the second is a string indicating the type of the file. */
@@ -967,11 +967,11 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args
     PathSet context;
     Path path = state.coerceToPath(pos, *args[1], context);
     if (!context.empty())
-        throw EvalError(format("string '%1%' cannot refer to other paths, at %2%") % path % pos);
+        throw EvalError(format("string ‘%1%’ cannot refer to other paths, at %2%") % path % pos);
 
     state.forceValue(*args[0]);
     if (args[0]->type != tLambda)
-        throw TypeError(format("first argument in call to 'filterSource' is not a function but %1%, at %2%") % showType(*args[0]) % pos);
+        throw TypeError(format("first argument in call to ‘filterSource’ is not a function but %1%, at %2%") % showType(*args[0]) % pos);
 
     FilterFromExpr filter(state, *args[0], pos);
 
@@ -1035,7 +1035,7 @@ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
     // !!! Should we create a symbol here or just do a lookup?
     Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
     if (i == args[1]->attrs->end())
-        throw EvalError(format("attribute '%1%' missing, at %2%") % attr % pos);
+        throw EvalError(format("attribute ‘%1%’ missing, at %2%") % attr % pos);
     // !!! add to stack trace?
     if (state.countCalls && i->pos) state.attrSelects[*i->pos]++;
     state.forceValue(*i->value);
@@ -1115,14 +1115,14 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
 
         Bindings::iterator j = v2.attrs->find(state.sName);
         if (j == v2.attrs->end())
-            throw TypeError(format("'name' attribute missing in a call to 'listToAttrs', at %1%") % pos);
+            throw TypeError(format("‘name’ attribute missing in a call to ‘listToAttrs’, at %1%") % pos);
         string name = state.forceStringNoCtx(*j->value, pos);
 
         Symbol sym = state.symbols.create(name);
         if (seen.find(sym) == seen.end()) {
             Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue));
             if (j2 == v2.attrs->end())
-                throw TypeError(format("'value' attribute missing in a call to 'listToAttrs', at %1%") % pos);
+                throw TypeError(format("‘value’ attribute missing in a call to ‘listToAttrs’, at %1%") % pos);
 
             v.attrs->push_back(Attr(sym, j2->value, j2->pos));
             seen.insert(sym);
@@ -1197,7 +1197,7 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
 {
     state.forceValue(*args[0]);
     if (args[0]->type != tLambda)
-        throw TypeError(format("'functionArgs' requires a function, at %1%") % pos);
+        throw TypeError(format("‘functionArgs’ requires a function, at %1%") % pos);
 
     if (!args[0]->lambda.fun->matchAttrs) {
         state.mkAttrs(v, 0);
@@ -1256,7 +1256,7 @@ static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value
 {
     state.forceList(*args[0], pos);
     if (args[0]->listSize() == 0)
-        throw Error(format("'tail' called on an empty list, at %1%") % pos);
+        throw Error(format("‘tail’ called on an empty list, at %1%") % pos);
     state.mkList(v, args[0]->listSize() - 1);
     for (unsigned int n = 0; n < v.listSize(); ++n)
         v.listElems()[n] = args[0]->listElems()[n + 1];
@@ -1565,7 +1565,7 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V
     PathSet context;
     string s = state.coerceToString(pos, *args[2], context);
 
-    if (start < 0) throw EvalError(format("negative start position in 'substring', at %1%") % pos);
+    if (start < 0) throw EvalError(format("negative start position in ‘substring’, at %1%") % pos);
 
     mkString(v, (unsigned int) start >= s.size() ? "" : string(s, start, len), context);
 }
@@ -1612,7 +1612,7 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
     string type = state.forceStringNoCtx(*args[0], pos);
     HashType ht = parseHashType(type);
     if (ht == htUnknown)
-      throw Error(format("unknown hash type '%1%', at %2%") % type % pos);
+      throw Error(format("unknown hash type ‘%1%’, at %2%") % type % pos);
 
     PathSet context; // discarded
     string s = state.forceString(*args[1], context, pos);
@@ -1622,7 +1622,7 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
 
 
 /* Match a regular expression against a string and return either
-   'null' or a list containing substring matches. */
+   ‘null’ or a list containing substring matches. */
 static void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
 {
     std::regex regex(state.forceStringNoCtx(*args[0], pos), std::regex::extended);
@@ -1674,7 +1674,7 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
     state.forceList(*args[0], pos);
     state.forceList(*args[1], pos);
     if (args[0]->listSize() != args[1]->listSize())
-        throw EvalError(format("'from' and 'to' arguments to 'replaceStrings' have different lengths, at %1%") % pos);
+        throw EvalError(format("‘from’ and ‘to’ arguments to ‘replaceStrings’ have different lengths, at %1%") % pos);
 
     vector<string> from;
     from.reserve(args[0]->listSize());
@@ -1765,17 +1765,17 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
             else if (n == "name")
                 name = state.forceStringNoCtx(*attr.value, *attr.pos);
             else
-                throw EvalError(format("unsupported argument '%1%' to '%2%', at %3%") % attr.name % who % attr.pos);
+                throw EvalError(format("unsupported argument ‘%1%’ to ‘%2%’, at %3%") % attr.name % who % attr.pos);
         }
 
         if (url.empty())
-            throw EvalError(format("'url' argument required, at %1%") % pos);
+            throw EvalError(format("‘url’ argument required, at %1%") % pos);
 
     } else
         url = state.forceStringNoCtx(*args[0], pos);
 
     if (state.restricted && !expectedHash)
-        throw Error(format("'%1%' is not allowed in restricted mode") % who);
+        throw Error(format("‘%1%’ is not allowed in restricted mode") % who);
 
     Path res = getDownloader()->downloadCached(state.store, url, unpack, name, expectedHash);
     mkString(v, res, PathSet({res}));
diff --git a/src/libexpr/primops/fetchgit.cc b/src/libexpr/primops/fetchgit.cc
index 96c68efdd5a8b8d88783665427d2bf518e9dac58..bd440c8c62ad710929172486236f76a3763cfa01 100644
--- a/src/libexpr/primops/fetchgit.cc
+++ b/src/libexpr/primops/fetchgit.cc
@@ -8,7 +8,7 @@ namespace nix {
 Path exportGit(ref<Store> store, const std::string & uri, const std::string & rev)
 {
     if (!isUri(uri))
-        throw EvalError(format("'%s' is not a valid URI") % uri);
+        throw EvalError(format("‘%s’ is not a valid URI") % uri);
 
     Path cacheDir = getCacheDir() + "/nix/git";
 
@@ -17,7 +17,7 @@ Path exportGit(ref<Store> store, const std::string & uri, const std::string & re
         runProgram("git", true, { "init", "--bare", cacheDir });
     }
 
-    Activity act(*logger, lvlInfo, format("fetching Git repository '%s'") % uri);
+    Activity act(*logger, lvlInfo, format("fetching Git repository ‘%s’") % uri);
 
     std::string localRef = "pid-" + std::to_string(getpid());
     Path localRefFile = cacheDir + "/refs/heads/" + localRef;
@@ -28,7 +28,7 @@ Path exportGit(ref<Store> store, const std::string & uri, const std::string & re
 
     unlink(localRefFile.c_str());
 
-    debug(format("got revision '%s'") % commitHash);
+    debug(format("got revision ‘%s’") % commitHash);
 
     // FIXME: should pipe this, or find some better way to extract a
     // revision.
@@ -45,7 +45,7 @@ Path exportGit(ref<Store> store, const std::string & uri, const std::string & re
 static void prim_fetchgit(EvalState & state, const Pos & pos, Value * * args, Value & v)
 {
     // FIXME: cut&paste from fetch().
-    if (state.restricted) throw Error("'fetchgit' is not allowed in restricted mode");
+    if (state.restricted) throw Error("‘fetchgit’ is not allowed in restricted mode");
 
     std::string url;
     std::string rev = "master";
@@ -63,11 +63,11 @@ static void prim_fetchgit(EvalState & state, const Pos & pos, Value * * args, Va
             else if (name == "rev")
                 rev = state.forceStringNoCtx(*attr.value, *attr.pos);
             else
-                throw EvalError(format("unsupported argument '%1%' to 'fetchgit', at %3%") % attr.name % attr.pos);
+                throw EvalError(format("unsupported argument ‘%1%’ to ‘fetchgit’, at %3%") % attr.name % attr.pos);
         }
 
         if (url.empty())
-            throw EvalError(format("'url' argument required, at %1%") % pos);
+            throw EvalError(format("‘url’ argument required, at %1%") % pos);
 
     } else
         url = state.forceStringNoCtx(*args[0], pos);
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 18d77347570b15b12d641a9f909db100a82f4ba7..0c6e3fb76d64d1f3d495a86cf17c85af3b2b85b7 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -37,7 +37,7 @@ void printGCWarning()
     if (!gcWarning) return;
     static bool haveWarned = false;
     warnOnce(haveWarned,
-        "you did not specify '--add-root'; "
+        "you did not specify ‘--add-root’; "
         "the result might be removed by the garbage collector");
 }
 
@@ -84,7 +84,7 @@ string getArg(const string & opt,
     Strings::iterator & i, const Strings::iterator & end)
 {
     ++i;
-    if (i == end) throw UsageError(format("'%1%' requires an argument") % opt);
+    if (i == end) throw UsageError(format("‘%1%’ requires an argument") % opt);
     return *i;
 }
 
@@ -204,7 +204,7 @@ struct LegacyArgs : public MixCommonArgs
         mkFlag(0, "show-trace", "show Nix expression stack trace in evaluation errors",
             &settings.showTrace);
 
-        mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'",
+        mkFlag(0, "no-gc-warning", "disable warning about not using ‘--add-root’",
             &gcWarning, false);
     }
 
@@ -223,7 +223,7 @@ struct LegacyArgs : public MixCommonArgs
         Strings ss(args);
         auto pos = ss.begin();
         if (!parseArg(pos, ss.end()))
-            throw UsageError(format("unexpected argument '%1%'") % args.front());
+            throw UsageError(format("unexpected argument ‘%1%’") % args.front());
         return true;
     }
 };
@@ -261,7 +261,7 @@ void showManPage(const string & name)
 {
     restoreSIGPIPE();
     execlp("man", "man", name.c_str(), NULL);
-    throw SysError(format("command 'man %1%' failed") % name.c_str());
+    throw SysError(format("command ‘man %1%’ failed") % name.c_str());
 }
 
 
@@ -283,13 +283,13 @@ int handleExceptions(const string & programName, std::function<void()> fun)
         return e.status;
     } catch (UsageError & e) {
         printError(
-            format(error + "%1%\nTry '%2% --help' for more information.")
+            format(error + "%1%\nTry ‘%2% --help’ for more information.")
             % e.what() % programName);
         return 1;
     } catch (BaseError & e) {
         printError(format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
         if (e.prefix() != "" && !settings.showTrace)
-            printError("(use '--show-trace' to show detailed location information)");
+            printError("(use ‘--show-trace’ to show detailed location information)");
         return e.status;
     } catch (std::bad_alloc & e) {
         printError(error + "out of memory");
@@ -333,7 +333,7 @@ RunPager::RunPager()
         execlp("pager", "pager", NULL);
         execlp("less", "less", NULL);
         execlp("more", "more", NULL);
-        throw SysError(format("executing '%1%'") % pager);
+        throw SysError(format("executing ‘%1%’") % pager);
     });
 
     if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh
index a147f9b4d453750f82b26c7654590d51f2deae5e..6d94a22f788ea24b092eabed8a6c0cf781b156c8 100644
--- a/src/libmain/shared.hh
+++ b/src/libmain/shared.hh
@@ -45,7 +45,7 @@ template<class N> N getIntArg(const string & opt,
     Strings::iterator & i, const Strings::iterator & end, bool allowUnit)
 {
     ++i;
-    if (i == end) throw UsageError(format("'%1%' requires an argument") % opt);
+    if (i == end) throw UsageError(format("‘%1%’ requires an argument") % opt);
     string s = *i;
     N multiplier = 1;
     if (allowUnit && !s.empty()) {
@@ -55,13 +55,13 @@ template<class N> N getIntArg(const string & opt,
             else if (u == 'M') multiplier = 1ULL << 20;
             else if (u == 'G') multiplier = 1ULL << 30;
             else if (u == 'T') multiplier = 1ULL << 40;
-            else throw UsageError(format("invalid unit specifier '%1%'") % u);
+            else throw UsageError(format("invalid unit specifier ‘%1%’") % u);
             s.resize(s.size() - 1);
         }
     }
     N n;
     if (!string2Int(s, n))
-        throw UsageError(format("'%1%' requires an integer argument") % opt);
+        throw UsageError(format("‘%1%’ requires an integer argument") % opt);
     return n * multiplier;
 }
 
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index 34a73f00204d0c407ceb03b15fdb3cb1cb9efbb8..3e07a2aa2b6083c7812af6fc1a630ebddd9a3293 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -39,7 +39,7 @@ struct BinaryCacheStoreAccessor : public FSAccessor
         std::string restPath = std::string(path, storePath.size());
 
         if (!store->isValidPath(storePath))
-            throw InvalidPath(format("path '%1%' is not a valid store path") % storePath);
+            throw InvalidPath(format("path ‘%1%’ is not a valid store path") % storePath);
 
         auto i = nars.find(storePath);
         if (i != nars.end()) return {i->second, restPath};
@@ -106,7 +106,7 @@ void BinaryCacheStore::init()
             auto value = trim(line.substr(colon + 1, std::string::npos));
             if (name == "StoreDir") {
                 if (value != storeDir)
-                    throw Error(format("binary cache '%s' is for Nix stores with prefix '%s', not '%s'")
+                    throw Error(format("binary cache ‘%s’ is for Nix stores with prefix ‘%s’, not ‘%s’")
                         % getUri() % value % storeDir);
             } else if (name == "WantMassQuery") {
                 wantMassQuery_ = value == "1";
@@ -153,7 +153,7 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
             if (ref != info.path)
                 queryPathInfo(ref);
         } catch (InvalidPath &) {
-            throw Error(format("cannot add '%s' to the binary cache because the reference '%s' is not valid")
+            throw Error(format("cannot add ‘%s’ to the binary cache because the reference ‘%s’ is not valid")
                 % info.path % ref);
         }
 
@@ -167,7 +167,7 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
     narInfo->narHash = hashString(htSHA256, *nar);
 
     if (info.narHash && info.narHash != narInfo->narHash)
-        throw Error(format("refusing to copy corrupted path '%1%' to binary cache") % info.path);
+        throw Error(format("refusing to copy corrupted path ‘%1%’ to binary cache") % info.path);
 
     auto accessor_ = std::dynamic_pointer_cast<BinaryCacheStoreAccessor>(accessor);
 
@@ -241,7 +241,7 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
     narInfo->fileSize = narCompressed->size();
 
     auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count();
-    printMsg(lvlTalkative, format("copying path '%1%' (%2% bytes, compressed %3$.1f%% in %4% ms) to binary cache")
+    printMsg(lvlTalkative, format("copying path ‘%1%’ (%2% bytes, compressed %3$.1f%% in %4% ms) to binary cache")
         % narInfo->path % narInfo->narSize
         % ((1.0 - (double) narCompressed->size() / nar->size()) * 100.0)
         % duration);
@@ -282,7 +282,7 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
 bool BinaryCacheStore::isValidPathUncached(const Path & storePath)
 {
     // FIXME: this only checks whether a .narinfo with a matching hash
-    // part exists. So 'f4kb...-foo' matches 'f4kb...-bar', even
+    // part exists. So ‘f4kb...-foo’ matches ‘f4kb...-bar’, even
     // though they shouldn't. Not easily fixed.
     return fileExists(narInfoFileFor(storePath));
 }
@@ -293,7 +293,7 @@ void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
 
     auto nar = getFile(info->url);
 
-    if (!nar) throw Error(format("file '%s' missing from binary cache") % info->url);
+    if (!nar) throw Error(format("file ‘%s’ missing from binary cache") % info->url);
 
     stats.narRead++;
     stats.narReadCompressedBytes += nar->size();
@@ -303,13 +303,13 @@ void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
     try {
         nar = decompress(info->compression, *nar);
     } catch (UnknownCompressionMethod &) {
-        throw Error(format("binary cache path '%s' uses unknown compression method '%s'")
+        throw Error(format("binary cache path ‘%s’ uses unknown compression method ‘%s’")
             % storePath % info->compression);
     }
 
     stats.narReadBytes += nar->size();
 
-    printMsg(lvlTalkative, format("exporting path '%1%' (%2% bytes)") % storePath % nar->size());
+    printMsg(lvlTalkative, format("exporting path ‘%1%’ (%2% bytes)") % storePath % nar->size());
 
     assert(nar->size() % 8 == 0);
 
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 716b0933f259ba016a5f0c24471414f396fe7dcc..ba51f85917f3d8469a26c75021dd126052e08e23 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -342,7 +342,7 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
     assert(waitees.find(waitee) != waitees.end());
     waitees.erase(waitee);
 
-    trace(format("waitee '%1%' done; %2% left") %
+    trace(format("waitee ‘%1%’ done; %2% left") %
         waitee->name % waitees.size());
 
     if (result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure) ++nrFailed;
@@ -414,7 +414,7 @@ static void commonChildInit(Pipe & logPipe)
     /* Reroute stdin to /dev/null. */
     int fdDevNull = open(pathNullDevice.c_str(), O_RDWR);
     if (fdDevNull == -1)
-        throw SysError(format("cannot open '%1%'") % pathNullDevice);
+        throw SysError(format("cannot open ‘%1%’") % pathNullDevice);
     if (dup2(fdDevNull, STDIN_FILENO) == -1)
         throw SysError("cannot dup null device into stdin");
     close(fdDevNull);
@@ -477,29 +477,29 @@ void UserLock::acquire()
     /* Get the members of the build-users-group. */
     struct group * gr = getgrnam(settings.buildUsersGroup.c_str());
     if (!gr)
-        throw Error(format("the group '%1%' specified in 'build-users-group' does not exist")
+        throw Error(format("the group ‘%1%’ specified in ‘build-users-group’ does not exist")
             % settings.buildUsersGroup);
     gid = gr->gr_gid;
 
     /* Copy the result of getgrnam. */
     Strings users;
     for (char * * p = gr->gr_mem; *p; ++p) {
-        debug(format("found build user '%1%'") % *p);
+        debug(format("found build user ‘%1%’") % *p);
         users.push_back(*p);
     }
 
     if (users.empty())
-        throw Error(format("the build users group '%1%' has no members")
+        throw Error(format("the build users group ‘%1%’ has no members")
             % settings.buildUsersGroup);
 
     /* Find a user account that isn't currently in use for another
        build. */
     for (auto & i : users) {
-        debug(format("trying user '%1%'") % i);
+        debug(format("trying user ‘%1%’") % i);
 
         struct passwd * pw = getpwnam(i.c_str());
         if (!pw)
-            throw Error(format("the user '%1%' in the group '%2%' does not exist")
+            throw Error(format("the user ‘%1%’ in the group ‘%2%’ does not exist")
                 % i % settings.buildUsersGroup);
 
         createDirs(settings.nixStateDir + "/userpool");
@@ -512,7 +512,7 @@ void UserLock::acquire()
 
         AutoCloseFD fd = open(fnUserLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600);
         if (!fd)
-            throw SysError(format("opening user lock '%1%'") % fnUserLock);
+            throw SysError(format("opening user lock ‘%1%’") % fnUserLock);
 
         if (lockFile(fd.get(), ltWrite, false)) {
             fdUserLock = std::move(fd);
@@ -522,7 +522,7 @@ void UserLock::acquire()
 
             /* Sanity check... */
             if (uid == getuid() || uid == geteuid())
-                throw Error(format("the Nix user should not be a member of '%1%'")
+                throw Error(format("the Nix user should not be a member of ‘%1%’")
                     % settings.buildUsersGroup);
 
 #if __linux__
@@ -533,7 +533,7 @@ void UserLock::acquire()
             int err = getgrouplist(pw->pw_name, pw->pw_gid,
                 supplementaryGIDs.data(), &ngroups);
             if (err == -1)
-                throw Error(format("failed to get list of supplementary groups for '%1%'") % pw->pw_name);
+                throw Error(format("failed to get list of supplementary groups for ‘%1%’") % pw->pw_name);
 
             supplementaryGIDs.resize(ngroups);
 #endif
@@ -543,7 +543,7 @@ void UserLock::acquire()
     }
 
     throw Error(format("all build users are currently in use; "
-        "consider creating additional users and adding them to the '%1%' group")
+        "consider creating additional users and adding them to the ‘%1%’ group")
         % settings.buildUsersGroup);
 }
 
@@ -630,7 +630,7 @@ HookInstance::HookInstance()
 
         execv(buildHook.c_str(), stringsToCharPtrs(args).data());
 
-        throw SysError(format("executing '%1%'") % buildHook);
+        throw SysError(format("executing ‘%1%’") % buildHook);
     });
 
     pid.setSeparatePG(true);
@@ -910,7 +910,7 @@ DerivationGoal::DerivationGoal(const Path & drvPath, const StringSet & wantedOut
     , buildMode(buildMode)
 {
     state = &DerivationGoal::getDerivation;
-    name = (format("building of '%1%'") % drvPath).str();
+    name = (format("building of ‘%1%’") % drvPath).str();
     trace("created");
 }
 
@@ -1021,7 +1021,7 @@ void DerivationGoal::loadDerivation()
     trace("loading derivation");
 
     if (nrFailed != 0) {
-        printError(format("cannot build missing derivation '%1%'") % drvPath);
+        printError(format("cannot build missing derivation ‘%1%’") % drvPath);
         done(BuildResult::MiscFailure);
         return;
     }
@@ -1062,7 +1062,7 @@ void DerivationGoal::haveDerivation()
         if (drv->outputs.size() != 1 ||
             drv->outputs.find("out") == drv->outputs.end() ||
             drv->outputs["out"].hashAlgo == "")
-            throw Error(format("cannot do a hash build of non-fixed-output derivation '%1%'") % drvPath);
+            throw Error(format("cannot do a hash build of non-fixed-output derivation ‘%1%’") % drvPath);
     }
 
     /* We are first going to try to create the invalid output paths
@@ -1084,7 +1084,7 @@ void DerivationGoal::outputsSubstituted()
     trace("all outputs substituted (maybe)");
 
     if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback) {
-        done(BuildResult::TransientFailure, (format("some substitutes for the outputs of derivation '%1%' failed (usually happens due to networking issues); try '--fallback' to build derivation from source ") % drvPath).str());
+        done(BuildResult::TransientFailure, (format("some substitutes for the outputs of derivation ‘%1%’ failed (usually happens due to networking issues); try ‘--fallback’ to build derivation from source ") % drvPath).str());
         return;
     }
 
@@ -1111,7 +1111,7 @@ void DerivationGoal::outputsSubstituted()
         return;
     }
     if (buildMode == bmCheck && nrInvalid > 0)
-        throw Error(format("some outputs of '%1%' are not valid, so checking is not possible") % drvPath);
+        throw Error(format("some outputs of ‘%1%’ are not valid, so checking is not possible") % drvPath);
 
     /* Otherwise, at least one of the output paths could not be
        produced using a substitute.  So we have to build instead. */
@@ -1128,7 +1128,7 @@ void DerivationGoal::outputsSubstituted()
     for (auto & i : drv->inputSrcs) {
         if (worker.store.isValidPath(i)) continue;
         if (!settings.useSubstitutes)
-            throw Error(format("dependency of '%1%' of '%2%' does not exist, and substitution is disabled")
+            throw Error(format("dependency of ‘%1%’ of ‘%2%’ does not exist, and substitution is disabled")
                 % i % drvPath);
         addWaitee(worker.makeSubstitutionGoal(i));
     }
@@ -1175,7 +1175,7 @@ void DerivationGoal::repairClosure()
     PathSet broken;
     for (auto & i : outputClosure) {
         if (worker.pathContentsGood(i)) continue;
-        printError(format("found corrupted or missing path '%1%' in the output closure of '%2%'") % i % drvPath);
+        printError(format("found corrupted or missing path ‘%1%’ in the output closure of ‘%2%’") % i % drvPath);
         Path drvPath2 = outputsToDrv[i];
         if (drvPath2 == "")
             addWaitee(worker.makeSubstitutionGoal(i, true));
@@ -1196,7 +1196,7 @@ void DerivationGoal::closureRepaired()
 {
     trace("closure repaired");
     if (nrFailed > 0)
-        throw Error(format("some paths in the output closure of derivation '%1%' could not be repaired") % drvPath);
+        throw Error(format("some paths in the output closure of derivation ‘%1%’ could not be repaired") % drvPath);
     done(BuildResult::AlreadyValid);
 }
 
@@ -1207,9 +1207,9 @@ void DerivationGoal::inputsRealised()
 
     if (nrFailed != 0) {
         if (!useDerivation)
-            throw Error(format("some dependencies of '%1%' are missing") % drvPath);
+            throw Error(format("some dependencies of ‘%1%’ are missing") % drvPath);
         printError(
-            format("cannot build derivation '%1%': %2% dependencies couldn't be built")
+            format("cannot build derivation ‘%1%’: %2% dependencies couldn't be built")
             % drvPath % nrFailed);
         done(BuildResult::DependencyFailed);
         return;
@@ -1225,7 +1225,7 @@ void DerivationGoal::inputsRealised()
 
     /* The outputs are referenceable paths. */
     for (auto & i : drv->outputs) {
-        debug(format("building path '%1%'") % i.second.path);
+        debug(format("building path ‘%1%’") % i.second.path);
         allPaths.insert(i.second.path);
     }
 
@@ -1244,7 +1244,7 @@ void DerivationGoal::inputsRealised()
                     worker.store.computeFSClosure(inDrv.outputs[j].path, inputPaths);
                 else
                     throw Error(
-                        format("derivation '%1%' requires non-existent output '%2%' from input derivation '%3%'")
+                        format("derivation ‘%1%’ requires non-existent output ‘%2%’ from input derivation ‘%3%’")
                         % drvPath % j % i.first);
         }
 
@@ -1283,7 +1283,7 @@ void DerivationGoal::tryToBuild()
        goal to sleep until another goal finishes, then try again. */
     for (auto & i : drv->outputs)
         if (pathIsLockedByMe(worker.store.toRealPath(i.second.path))) {
-            debug(format("putting derivation '%1%' to sleep because '%2%' is locked by another goal")
+            debug(format("putting derivation ‘%1%’ to sleep because ‘%2%’ is locked by another goal")
                 % drvPath % i.second.path);
             worker.waitForAnyGoal(shared_from_this());
             return;
@@ -1312,7 +1312,7 @@ void DerivationGoal::tryToBuild()
        build this derivation, so no further checks are necessary. */
     validPaths = checkPathValidity(true, buildMode == bmRepair);
     if (buildMode != bmCheck && validPaths.size() == drv->outputs.size()) {
-        debug(format("skipping build of derivation '%1%', someone beat us to it") % drvPath);
+        debug(format("skipping build of derivation ‘%1%’, someone beat us to it") % drvPath);
         outputLocks.setDeletion(true);
         done(BuildResult::AlreadyValid);
         return;
@@ -1327,7 +1327,7 @@ void DerivationGoal::tryToBuild()
     for (auto & i : drv->outputs) {
         Path path = i.second.path;
         if (worker.store.isValidPath(path)) continue;
-        debug(format("removing invalid path '%1%'") % path);
+        debug(format("removing invalid path ‘%1%’") % path);
         deletePath(worker.store.toRealPath(path));
     }
 
@@ -1396,7 +1396,7 @@ void replaceValidPath(const Path & storePath, const Path tmpPath)
     if (pathExists(storePath))
         rename(storePath.c_str(), oldPath.c_str());
     if (rename(tmpPath.c_str(), storePath.c_str()) == -1)
-        throw SysError(format("moving '%1%' to '%2%'") % tmpPath % storePath);
+        throw SysError(format("moving ‘%1%’ to ‘%2%’") % tmpPath % storePath);
     deletePath(oldPath);
 }
 
@@ -1416,7 +1416,7 @@ void DerivationGoal::buildDone()
        child */
     int status = hook ? hook->pid.wait(true) : pid.wait(true);
 
-    debug(format("builder process for '%1%' finished") % drvPath);
+    debug(format("builder process for ‘%1%’ finished") % drvPath);
 
     /* So the child is gone now. */
     worker.childTerminated(this);
@@ -1470,7 +1470,7 @@ void DerivationGoal::buildDone()
                     if (pathExists(chrootRootDir + i))
                         rename((chrootRootDir + i).c_str(), i.c_str());
 
-            std::string msg = (format("builder for '%1%' %2%")
+            std::string msg = (format("builder for ‘%1%’ %2%")
                 % drvPath % statusToString(status)).str();
 
             if (!settings.verboseBuild && !logTail.empty()) {
@@ -1583,12 +1583,12 @@ HookReply DerivationGoal::tryBuildHook()
         writeToStderr(s);
     }
 
-    debug(format("hook reply is '%1%'") % reply);
+    debug(format("hook reply is ‘%1%’") % reply);
 
     if (reply == "decline" || reply == "postpone")
         return reply == "decline" ? rpDecline : rpPostpone;
     else if (reply != "accept")
-        throw Error(format("bad hook reply '%1%'") % reply);
+        throw Error(format("bad hook reply ‘%1%’") % reply);
 
     printMsg(lvlTalkative, format("using hook to build path(s) %1%") % showPaths(missingPaths));
 
@@ -1631,7 +1631,7 @@ HookReply DerivationGoal::tryBuildHook()
 void chmod_(const Path & path, mode_t mode)
 {
     if (chmod(path.c_str(), mode) == -1)
-        throw SysError(format("setting permissions on '%1%'") % path);
+        throw SysError(format("setting permissions on ‘%1%’") % path);
 }
 
 
@@ -1655,7 +1655,7 @@ void DerivationGoal::startBuilder()
     /* Right platform? */
     if (!drv->canBuildLocally()) {
         throw Error(
-            format("a '%1%' is required to build '%3%', but I am a '%2%'")
+            format("a ‘%1%’ is required to build ‘%3%’, but I am a ‘%2%’")
             % drv->platform % settings.thisSystem % drvPath);
     }
 
@@ -1673,15 +1673,15 @@ void DerivationGoal::startBuilder()
             /* deprecated alias */
             settings.get("build-use-chroot", string("false")));
         if (x != "true" && x != "false" && x != "relaxed")
-            throw Error("option 'build-use-sandbox' must be set to one of 'true', 'false' or 'relaxed'");
+            throw Error("option ‘build-use-sandbox’ must be set to one of ‘true’, ‘false’ or ‘relaxed’");
         if (x == "true") {
             if (get(drv->env, "__noChroot") == "1")
-                throw Error(format("derivation '%1%' has '__noChroot' set, "
-                    "but that's not allowed when 'build-use-sandbox' is 'true'") % drvPath);
+                throw Error(format("derivation ‘%1%’ has ‘__noChroot’ set, "
+                    "but that's not allowed when ‘build-use-sandbox’ is ‘true’") % drvPath);
 #if __APPLE__
             if (additionalSandboxProfile != "")
-                throw Error(format("derivation '%1%' specifies a sandbox profile, "
-                    "but this is only allowed when 'build-use-sandbox' is 'relaxed'") % drvPath);
+                throw Error(format("derivation ‘%1%’ specifies a sandbox profile, "
+                    "but this is only allowed when ‘build-use-sandbox’ is ‘relaxed’") % drvPath);
 #endif
             useChroot = true;
         }
@@ -1795,7 +1795,7 @@ void DerivationGoal::startBuilder()
     string s = get(drv->env, "exportReferencesGraph");
     Strings ss = tokenizeString<Strings>(s);
     if (ss.size() % 2 != 0)
-        throw BuildError(format("odd number of tokens in 'exportReferencesGraph': '%1%'") % s);
+        throw BuildError(format("odd number of tokens in ‘exportReferencesGraph’: ‘%1%’") % s);
     for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
         string fileName = *i++;
         checkStoreName(fileName); /* !!! abuse of this function */
@@ -1803,11 +1803,11 @@ void DerivationGoal::startBuilder()
         /* Check that the store path is valid. */
         Path storePath = *i++;
         if (!worker.store.isInStore(storePath))
-            throw BuildError(format("'exportReferencesGraph' contains a non-store path '%1%'")
+            throw BuildError(format("‘exportReferencesGraph’ contains a non-store path ‘%1%’")
                 % storePath);
         storePath = worker.store.toStorePath(storePath);
         if (!worker.store.isValidPath(storePath))
-            throw BuildError(format("'exportReferencesGraph' contains an invalid path '%1%'")
+            throw BuildError(format("‘exportReferencesGraph’ contains an invalid path ‘%1%’")
                 % storePath);
 
         /* If there are derivations in the graph, then include their
@@ -1846,7 +1846,7 @@ void DerivationGoal::startBuilder()
 
         for (auto & p : filesToChown)
             if (chown(p.c_str(), buildUser.getUID(), buildUser.getGID()) == -1)
-                throw SysError(format("cannot change ownership of '%1%'") % p);
+                throw SysError(format("cannot change ownership of ‘%1%’") % p);
     }
 
 
@@ -1893,7 +1893,7 @@ void DerivationGoal::startBuilder()
                 if (worker.store.isInStore(i.second.source))
                     worker.store.computeFSClosure(worker.store.toStorePath(i.second.source), closure);
             } catch (Error & e) {
-                throw Error(format("while processing 'build-sandbox-paths': %s") % e.what());
+                throw Error(format("while processing ‘build-sandbox-paths’: %s") % e.what());
             }
         for (auto & i : closure)
             dirsInChroot[i] = i;
@@ -1919,7 +1919,7 @@ void DerivationGoal::startBuilder()
                 }
             }
             if (!found)
-                throw Error(format("derivation '%1%' requested impure path '%2%', but it was not in allowed-impure-host-deps ('%3%')") % drvPath % i % allowed);
+                throw Error(format("derivation ‘%1%’ requested impure path ‘%2%’, but it was not in allowed-impure-host-deps (‘%3%’)") % drvPath % i % allowed);
 
             dirsInChroot[i] = i;
         }
@@ -1935,13 +1935,13 @@ void DerivationGoal::startBuilder()
         /* Clean up the chroot directory automatically. */
         autoDelChroot = std::make_shared<AutoDelete>(chrootRootDir);
 
-        printMsg(lvlChatty, format("setting up chroot environment in '%1%'") % chrootRootDir);
+        printMsg(lvlChatty, format("setting up chroot environment in ‘%1%’") % chrootRootDir);
 
         if (mkdir(chrootRootDir.c_str(), 0750) == -1)
-            throw SysError(format("cannot create '%1%'") % chrootRootDir);
+            throw SysError(format("cannot create ‘%1%’") % chrootRootDir);
 
         if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
-            throw SysError(format("cannot change ownership of '%1%'") % chrootRootDir);
+            throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir);
 
         /* Create a writable /tmp in the chroot.  Many builders need
            this.  (Of course they should really respect $TMPDIR
@@ -1985,13 +1985,13 @@ void DerivationGoal::startBuilder()
         chmod_(chrootStoreDir, 01775);
 
         if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
-            throw SysError(format("cannot change ownership of '%1%'") % chrootStoreDir);
+            throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         for (auto & i : inputPaths) {
             Path r = worker.store.toRealPath(i);
             struct stat st;
             if (lstat(r.c_str(), &st))
-                throw SysError(format("getting attributes of path '%1%'") % i);
+                throw SysError(format("getting attributes of path ‘%1%’") % i);
             if (S_ISDIR(st.st_mode))
                 dirsInChroot[i] = r;
             else {
@@ -2002,7 +2002,7 @@ void DerivationGoal::startBuilder()
                        which is quite possible after a `nix-store
                        --optimise'. */
                     if (errno != EMLINK)
-                        throw SysError(format("linking '%1%' to '%2%'") % p % i);
+                        throw SysError(format("linking ‘%1%’ to ‘%2%’") % p % i);
                     StringSink sink;
                     dumpPath(r, sink);
                     StringSource source(*sink.s);
@@ -2030,7 +2030,7 @@ void DerivationGoal::startBuilder()
     else {
 
         if (pathExists(homeDir))
-            throw Error(format("directory '%1%' exists; please remove it") % homeDir);
+            throw Error(format("directory ‘%1%’ exists; please remove it") % homeDir);
 
         /* We're not doing a chroot build, but we have some valid
            output paths.  Since we can't just overwrite or delete
@@ -2056,7 +2056,7 @@ void DerivationGoal::startBuilder()
     }
 
     if (settings.preBuildHook != "") {
-        printMsg(lvlChatty, format("executing pre-build hook '%1%'")
+        printMsg(lvlChatty, format("executing pre-build hook ‘%1%’")
             % settings.preBuildHook);
         auto args = useChroot ? Strings({drvPath, chrootRootDir}) :
             Strings({ drvPath });
@@ -2075,7 +2075,7 @@ void DerivationGoal::startBuilder()
                 if (line == "extra-sandbox-paths" || line == "extra-chroot-dirs") {
                     state = stExtraChrootDirs;
                 } else {
-                    throw Error(format("unknown pre-build hook command '%1%'")
+                    throw Error(format("unknown pre-build hook command ‘%1%’")
                         % line);
                 }
             } else if (state == stExtraChrootDirs) {
@@ -2093,7 +2093,7 @@ void DerivationGoal::startBuilder()
     }
 
     /* Run the builder. */
-    printMsg(lvlChatty, format("executing builder '%1%'") % drv->builder);
+    printMsg(lvlChatty, format("executing builder ‘%1%’") % drv->builder);
 
     /* Create the log file. */
     Path logFile = openLogFile();
@@ -2288,13 +2288,13 @@ void DerivationGoal::runChild()
                 vector<string> fields = tokenizeString<vector<string> >(i, " ");
                 string fs = decodeOctalEscaped(fields.at(4));
                 if (mount(0, fs.c_str(), 0, MS_PRIVATE, 0) == -1)
-                    throw SysError(format("unable to make filesystem '%1%' private") % fs);
+                    throw SysError(format("unable to make filesystem ‘%1%’ private") % fs);
             }
 
             /* Bind-mount chroot directory to itself, to treat it as a
                different filesystem from /, as needed for pivot_root. */
             if (mount(chrootRootDir.c_str(), chrootRootDir.c_str(), 0, MS_BIND, 0) == -1)
-                throw SysError(format("unable to bind mount '%1%'") % chrootRootDir);
+                throw SysError(format("unable to bind mount ‘%1%’") % chrootRootDir);
 
             /* Set up a nearly empty /dev, unless the user asked to
                bind-mount the host /dev. */
@@ -2340,12 +2340,12 @@ void DerivationGoal::runChild()
                 Path source = i.second.source;
                 Path target = chrootRootDir + i.first;
                 if (source == "/proc") continue; // backwards compatibility
-                debug(format("bind mounting '%1%' to '%2%'") % source % target);
+                debug(format("bind mounting ‘%1%’ to ‘%2%’") % source % target);
                 if (stat(source.c_str(), &st) == -1) {
                     if (i.second.optional && errno == ENOENT)
                         continue;
                     else
-                        throw SysError(format("getting attributes of path '%1%'") % source);
+                        throw SysError(format("getting attributes of path ‘%1%’") % source);
                 }
                 if (S_ISDIR(st.st_mode))
                     createDirs(target);
@@ -2354,7 +2354,7 @@ void DerivationGoal::runChild()
                     writeFile(target, "");
                 }
                 if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REC, 0) == -1)
-                    throw SysError(format("bind mount from '%1%' to '%2%' failed") % source % target);
+                    throw SysError(format("bind mount from ‘%1%’ to ‘%2%’ failed") % source % target);
             }
 
             /* Bind a new instance of procfs on /proc. */
@@ -2392,16 +2392,16 @@ void DerivationGoal::runChild()
 
             /* Do the chroot(). */
             if (chdir(chrootRootDir.c_str()) == -1)
-                throw SysError(format("cannot change directory to '%1%'") % chrootRootDir);
+                throw SysError(format("cannot change directory to ‘%1%’") % chrootRootDir);
 
             if (mkdir("real-root", 0) == -1)
                 throw SysError("cannot create real-root directory");
 
             if (pivot_root(".", "real-root") == -1)
-                throw SysError(format("cannot pivot old root directory onto '%1%'") % (chrootRootDir + "/real-root"));
+                throw SysError(format("cannot pivot old root directory onto ‘%1%’") % (chrootRootDir + "/real-root"));
 
             if (chroot(".") == -1)
-                throw SysError(format("cannot change root directory to '%1%'") % chrootRootDir);
+                throw SysError(format("cannot change root directory to ‘%1%’") % chrootRootDir);
 
             if (umount2("real-root", MNT_DETACH) == -1)
                 throw SysError("cannot unmount real root filesystem");
@@ -2422,7 +2422,7 @@ void DerivationGoal::runChild()
 #endif
 
         if (chdir(tmpDirInSandbox.c_str()) == -1)
-            throw SysError(format("changing into '%1%'") % tmpDir);
+            throw SysError(format("changing into ‘%1%’") % tmpDir);
 
         /* Close all other file descriptors. */
         closeMostFDs(set<int>());
@@ -2564,7 +2564,7 @@ void DerivationGoal::runChild()
                 if (lstat(path.c_str(), &st)) {
                     if (i.second.optional && errno == ENOENT)
                         continue;
-                    throw SysError(format("getting attributes of path '%1%'") % path);
+                    throw SysError(format("getting attributes of path ‘%1%’") % path);
                 }
                 if (S_ISDIR(st.st_mode))
                     sandboxProfile += (format("\t(subpath \"%1%\")\n") % path).str();
@@ -2619,7 +2619,7 @@ void DerivationGoal::runChild()
                 if (drv->builder == "builtin:fetchurl")
                     builtinFetchurl(*drv);
                 else
-                    throw Error(format("unsupported builtin function '%1%'") % string(drv->builder, 8));
+                    throw Error(format("unsupported builtin function ‘%1%’") % string(drv->builder, 8));
                 _exit(0);
             } catch (std::exception & e) {
                 writeFull(STDERR_FILENO, "error: " + string(e.what()) + "\n");
@@ -2629,7 +2629,7 @@ void DerivationGoal::runChild()
 
         execve(builder, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
 
-        throw SysError(format("executing '%1%'") % drv->builder);
+        throw SysError(format("executing ‘%1%’") % drv->builder);
 
     } catch (std::exception & e) {
         writeFull(STDERR_FILENO, "\1while setting up the build environment: " + string(e.what()) + "\n");
@@ -2651,7 +2651,7 @@ PathSet parseReferenceSpecifiers(Store & store, const BasicDerivation & drv, str
         else if (drv.outputs.find(i) != drv.outputs.end())
             result.insert(drv.outputs.find(i)->second.path);
         else throw BuildError(
-            format("derivation contains an illegal reference specifier '%1%'") % i);
+            format("derivation contains an illegal reference specifier ‘%1%’") % i);
     }
     return result;
 }
@@ -2694,7 +2694,7 @@ void DerivationGoal::registerOutputs()
                     replaceValidPath(path, actualPath);
                 else
                     if (buildMode != bmCheck && rename(actualPath.c_str(), worker.store.toRealPath(path).c_str()) == -1)
-                        throw SysError(format("moving build output '%1%' from the sandbox to the Nix store") % path);
+                        throw SysError(format("moving build output ‘%1%’ from the sandbox to the Nix store") % path);
             }
             if (buildMode != bmCheck) actualPath = worker.store.toRealPath(path);
         } else {
@@ -2711,9 +2711,9 @@ void DerivationGoal::registerOutputs()
         if (lstat(actualPath.c_str(), &st) == -1) {
             if (errno == ENOENT)
                 throw BuildError(
-                    format("builder for '%1%' failed to produce output path '%2%'")
+                    format("builder for ‘%1%’ failed to produce output path ‘%2%’")
                     % drvPath % path);
-            throw SysError(format("getting attributes of path '%1%'") % actualPath);
+            throw SysError(format("getting attributes of path ‘%1%’") % actualPath);
         }
 
 #ifndef __CYGWIN__
@@ -2723,13 +2723,13 @@ void DerivationGoal::registerOutputs()
            user. */
         if ((!S_ISLNK(st.st_mode) && (st.st_mode & (S_IWGRP | S_IWOTH))) ||
             (buildUser.enabled() && st.st_uid != buildUser.getUID()))
-            throw BuildError(format("suspicious ownership or permission on '%1%'; rejecting this build output") % path);
+            throw BuildError(format("suspicious ownership or permission on ‘%1%’; rejecting this build output") % path);
 #endif
 
         /* Apply hash rewriting if necessary. */
         bool rewritten = false;
         if (!outputRewrites.empty()) {
-            printError(format("warning: rewriting hashes in '%1%'; cross fingers") % path);
+            printError(format("warning: rewriting hashes in ‘%1%’; cross fingers") % path);
 
             /* Canonicalise first.  This ensures that the path we're
                rewriting doesn't contain a hard link to /etc/shadow or
@@ -2760,7 +2760,7 @@ void DerivationGoal::registerOutputs()
                    execute permission. */
                 if (!S_ISREG(st.st_mode) || (st.st_mode & S_IXUSR) != 0)
                     throw BuildError(
-                        format("output path '%1%' should be a non-executable regular file") % path);
+                        format("output path ‘%1%’ should be a non-executable regular file") % path);
             }
 
             /* Check the hash. In hash mode, move the path produced by
@@ -2768,7 +2768,7 @@ void DerivationGoal::registerOutputs()
             Hash h2 = recursive ? hashPath(h.type, actualPath).first : hashFile(h.type, actualPath);
             if (buildMode == bmHash) {
                 Path dest = worker.store.makeFixedOutputPath(recursive, h2, drv->env["name"]);
-                printError(format("build produced path '%1%' with %2% hash '%3%'")
+                printError(format("build produced path ‘%1%’ with %2% hash ‘%3%’")
                     % dest % printHashType(h.type) % printHash16or32(h2));
                 if (worker.store.isValidPath(dest))
                     return;
@@ -2777,14 +2777,14 @@ void DerivationGoal::registerOutputs()
                     PathLocks outputLocks({actualDest});
                     deletePath(actualDest);
                     if (rename(actualPath.c_str(), actualDest.c_str()) == -1)
-                        throw SysError(format("moving '%1%' to '%2%'") % actualPath % dest);
+                        throw SysError(format("moving ‘%1%’ to ‘%2%’") % actualPath % dest);
                 }
                 path = dest;
                 actualPath = actualDest;
             } else {
                 if (h != h2)
                     throw BuildError(
-                        format("output path '%1%' has %2% hash '%3%' when '%4%' was expected")
+                        format("output path ‘%1%’ has %2% hash ‘%3%’ when ‘%4%’ was expected")
                         % path % i.second.hashAlgo % printHash16or32(h2) % printHash16or32(h));
             }
         }
@@ -2798,7 +2798,7 @@ void DerivationGoal::registerOutputs()
            contained in it.  Compute the SHA-256 NAR hash at the same
            time.  The hash is stored in the database so that we can
            verify later on whether nobody has messed with the store. */
-        Activity act(*logger, lvlTalkative, format("scanning for references inside '%1%'") % path);
+        Activity act(*logger, lvlTalkative, format("scanning for references inside ‘%1%’") % path);
         HashResult hash;
         PathSet references = scanForReferences(actualPath, allPaths, hash);
 
@@ -2810,11 +2810,11 @@ void DerivationGoal::registerOutputs()
                     Path dst = worker.store.toRealPath(path + checkSuffix);
                     deletePath(dst);
                     if (rename(actualPath.c_str(), dst.c_str()))
-                        throw SysError(format("renaming '%1%' to '%2%'") % actualPath % dst);
-                    throw Error(format("derivation '%1%' may not be deterministic: output '%2%' differs from '%3%'")
+                        throw SysError(format("renaming ‘%1%’ to ‘%2%’") % actualPath % dst);
+                    throw Error(format("derivation ‘%1%’ may not be deterministic: output ‘%2%’ differs from ‘%3%’")
                         % drvPath % path % dst);
                 } else
-                    throw Error(format("derivation '%1%' may not be deterministic: output '%2%' differs")
+                    throw Error(format("derivation ‘%1%’ may not be deterministic: output ‘%2%’ differs")
                         % drvPath % path);
             }
 
@@ -2834,9 +2834,9 @@ void DerivationGoal::registerOutputs()
         for (auto & i : inputPaths) {
             PathSet::iterator j = references.find(i);
             if (j == references.end())
-                debug(format("unreferenced input: '%1%'") % i);
+                debug(format("unreferenced input: ‘%1%’") % i);
             else
-                debug(format("referenced input: '%1%'") % i);
+                debug(format("referenced input: ‘%1%’") % i);
         }
 
         /* Enforce `allowedReferences' and friends. */
@@ -2872,7 +2872,7 @@ void DerivationGoal::registerOutputs()
                     badPathsStr += "\n\t";
                     badPathsStr += i;
                 }
-                throw BuildError(format("output '%1%' is not allowed to refer to the following paths:%2%") % actualPath % badPathsStr);
+                throw BuildError(format("output ‘%1%’ is not allowed to refer to the following paths:%2%") % actualPath % badPathsStr);
             }
         };
 
@@ -2909,11 +2909,11 @@ void DerivationGoal::registerOutputs()
                 Path prev = i->path + checkSuffix;
                 if (pathExists(prev))
                     throw NotDeterministic(
-                        format("output '%1%' of '%2%' differs from '%3%' from previous round")
+                        format("output ‘%1%’ of ‘%2%’ differs from ‘%3%’ from previous round")
                         % i->path % drvPath % prev);
                 else
                     throw NotDeterministic(
-                        format("output '%1%' of '%2%' differs from previous round")
+                        format("output ‘%1%’ of ‘%2%’ differs from previous round")
                         % i->path % drvPath);
             }
         abort(); // shouldn't happen
@@ -2926,7 +2926,7 @@ void DerivationGoal::registerOutputs()
             if (curRound < nrRounds) {
                 Path dst = i.second.path + checkSuffix;
                 if (rename(i.second.path.c_str(), dst.c_str()))
-                    throw SysError(format("renaming '%1%' to '%2%'") % i.second.path % dst);
+                    throw SysError(format("renaming ‘%1%’ to ‘%2%’") % i.second.path % dst);
             }
         }
 
@@ -2965,7 +2965,7 @@ Path DerivationGoal::openLogFile()
         % (settings.compressLog ? ".bz2" : "")).str();
 
     fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
-    if (!fdLogFile) throw SysError(format("creating log file '%1%'") % logFileName);
+    if (!fdLogFile) throw SysError(format("creating log file ‘%1%’") % logFileName);
 
     logFileSink = std::make_shared<FdSink>(fdLogFile.get());
 
@@ -2993,7 +2993,7 @@ void DerivationGoal::deleteTmpDir(bool force)
     if (tmpDir != "") {
         if (settings.keepFailed && !force) {
             printError(
-                format("note: keeping build directory '%2%'")
+                format("note: keeping build directory ‘%2%’")
                 % drvPath % tmpDir);
             chmod(tmpDir.c_str(), 0755);
         }
@@ -3177,7 +3177,7 @@ SubstitutionGoal::SubstitutionGoal(const Path & storePath, Worker & worker, bool
 {
     this->storePath = storePath;
     state = &SubstitutionGoal::init;
-    name = (format("substitution of '%1%'") % storePath).str();
+    name = (format("substitution of ‘%1%’") % storePath).str();
     trace("created");
 }
 
@@ -3215,7 +3215,7 @@ void SubstitutionGoal::init()
     }
 
     if (settings.readOnlyMode)
-        throw Error(format("cannot substitute path '%1%' - no write access to the Nix store") % storePath);
+        throw Error(format("cannot substitute path ‘%1%’ - no write access to the Nix store") % storePath);
 
     subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
 
@@ -3230,7 +3230,7 @@ void SubstitutionGoal::tryNext()
     if (subs.size() == 0) {
         /* None left.  Terminate this goal and let someone else deal
            with it. */
-        debug(format("path '%1%' is required, but there is no substituter that can build it") % storePath);
+        debug(format("path ‘%1%’ is required, but there is no substituter that can build it") % storePath);
 
         /* Hack: don't indicate failure if there were no substituters.
            In that case the calling derivation should just do a
@@ -3261,7 +3261,7 @@ void SubstitutionGoal::tryNext()
        signature. LocalStore::addToStore() also checks for this, but
        only after we've downloaded the path. */
     if (worker.store.requireSigs && !info->checkSignatures(worker.store, worker.store.publicKeys)) {
-        printInfo(format("warning: substituter '%s' does not have a valid signature for path '%s'")
+        printInfo(format("warning: substituter ‘%s’ does not have a valid signature for path ‘%s’")
             % sub->getUri() % storePath);
         tryNext();
         return;
@@ -3285,7 +3285,7 @@ void SubstitutionGoal::referencesValid()
     trace("all references realised");
 
     if (nrFailed > 0) {
-        debug(format("some references of path '%1%' could not be realised") % storePath);
+        debug(format("some references of path ‘%1%’ could not be realised") % storePath);
         amDone(nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed);
         return;
     }
@@ -3312,7 +3312,7 @@ void SubstitutionGoal::tryToRun()
         return;
     }
 
-    printInfo(format("fetching path '%1%'...") % storePath);
+    printInfo(format("fetching path ‘%1%’...") % storePath);
 
     outPipe.create();
 
@@ -3359,7 +3359,7 @@ void SubstitutionGoal::finished()
     worker.markContentsGood(storePath);
 
     printMsg(lvlChatty,
-        format("substitution of path '%1%' succeeded") % storePath);
+        format("substitution of path ‘%1%’ succeeded") % storePath);
 
     amDone(ecSuccess);
 }
@@ -3589,7 +3589,7 @@ void Worker::run(const Goals & _topGoals)
             waitForInput();
         else {
             if (awake.empty() && settings.maxBuildJobs == 0) throw Error(
-                "unable to start any build; either increase '--max-jobs' "
+                "unable to start any build; either increase ‘--max-jobs’ "
                 "or enable distributed builds");
             assert(!awake.empty());
         }
@@ -3744,7 +3744,7 @@ bool Worker::pathContentsGood(const Path & path)
 {
     std::map<Path, bool>::iterator i = pathContentsGoodCache.find(path);
     if (i != pathContentsGoodCache.end()) return i->second;
-    printInfo(format("checking path '%1%'...") % path);
+    printInfo(format("checking path ‘%1%’...") % path);
     auto info = store.queryPathInfo(path);
     bool res;
     if (!pathExists(path))
@@ -3755,7 +3755,7 @@ bool Worker::pathContentsGood(const Path & path)
         res = info->narHash == nullHash || info->narHash == current.first;
     }
     pathContentsGoodCache[path] = res;
-    if (!res) printError(format("path '%1%' is corrupted or missing!") % path);
+    if (!res) printError(format("path ‘%1%’ is corrupted or missing!") % path);
     return res;
 }
 
@@ -3829,7 +3829,7 @@ void LocalStore::ensurePath(const Path & path)
     worker.run(goals);
 
     if (goal->getExitCode() != Goal::ecSuccess)
-        throw Error(worker.exitStatus(), "path '%s' does not exist and cannot be created", path);
+        throw Error(worker.exitStatus(), "path ‘%s’ does not exist and cannot be created", path);
 }
 
 
@@ -3850,7 +3850,7 @@ void LocalStore::repairPath(const Path & path)
             goals.insert(worker.makeDerivationGoal(deriver, StringSet(), bmRepair));
             worker.run(goals);
         } else
-            throw Error(worker.exitStatus(), "cannot repair path '%s'", path);
+            throw Error(worker.exitStatus(), "cannot repair path ‘%s’", path);
     }
 }
 
diff --git a/src/libstore/builtins.cc b/src/libstore/builtins.cc
index a9c86599eed3c42085599da538308d4023834807..a30f30906f016df95d80977eca439a933b17dbcc 100644
--- a/src/libstore/builtins.cc
+++ b/src/libstore/builtins.cc
@@ -10,7 +10,7 @@ void builtinFetchurl(const BasicDerivation & drv)
 {
     auto getAttr = [&](const string & name) {
         auto i = drv.env.find(name);
-        if (i == drv.env.end()) throw Error(format("attribute '%s' missing") % name);
+        if (i == drv.env.end()) throw Error(format("attribute ‘%s’ missing") % name);
         return i->second;
     };
 
@@ -56,7 +56,7 @@ void builtinFetchurl(const BasicDerivation & drv)
     auto executable = drv.env.find("executable");
     if (executable != drv.env.end() && executable->second == "1") {
         if (chmod(storePath.c_str(), 0755) == -1)
-            throw SysError(format("making '%1%' executable") % storePath);
+            throw SysError(format("making ‘%1%’ executable") % storePath);
     }
 }
 
diff --git a/src/libstore/crypto.hh b/src/libstore/crypto.hh
index eb299b90f52b45194d69943dca9514491ecf4d20..9110af3aa9e51ff49418849097822cef0931c2bd 100644
--- a/src/libstore/crypto.hh
+++ b/src/libstore/crypto.hh
@@ -12,7 +12,7 @@ struct Key
     std::string key;
 
     /* Construct Key from a string in the format
-       '<name>:<key-in-base64>'. */
+       ‘<name>:<key-in-base64>’. */
     Key(const std::string & s);
 
 protected:
@@ -44,7 +44,7 @@ private:
 
 typedef std::map<std::string, PublicKey> PublicKeys;
 
-/* Return true iff 'sig' is a correct signature over 'data' using one
+/* Return true iff ‘sig’ is a correct signature over ‘data’ using one
    of the given public keys. */
 bool verifyDetached(const std::string & data, const std::string & sig,
     const PublicKeys & publicKeys);
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc
index d4bcad7fe1d5755022757a889907b995f9fa3c8a..5562d46892a89f62a69ffeab13edc236f48fc9b0 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -21,7 +21,7 @@ void DerivationOutput::parseHashInfo(bool & recursive, Hash & hash) const
 
     HashType hashType = parseHashType(algo);
     if (hashType == htUnknown)
-        throw Error(format("unknown hash algorithm '%1%'") % algo);
+        throw Error(format("unknown hash algorithm ‘%1%’") % algo);
 
     hash = parseHash(hashType, this->hash);
 }
@@ -31,7 +31,7 @@ Path BasicDerivation::findOutput(const string & id) const
 {
     auto i = outputs.find(id);
     if (i == outputs.end())
-        throw Error(format("derivation has no output '%1%'") % id);
+        throw Error(format("derivation has no output ‘%1%’") % id);
     return i->second.path;
 }
 
@@ -97,7 +97,7 @@ static void expect(std::istream & str, const string & s)
     char s2[s.size()];
     str.read(s2, s.size());
     if (string(s2, s.size()) != s)
-        throw FormatError(format("expected string '%1%'") % s);
+        throw FormatError(format("expected string ‘%1%’") % s);
 }
 
 
@@ -124,7 +124,7 @@ static Path parsePath(std::istream & str)
 {
     string s = parseString(str);
     if (s.size() == 0 || s[0] != '/')
-        throw FormatError(format("bad path '%1%' in derivation") % s);
+        throw FormatError(format("bad path ‘%1%’ in derivation") % s);
     return s;
 }
 
@@ -207,7 +207,7 @@ Derivation readDerivation(const Path & drvPath)
     try {
         return parseDerivation(readFile(drvPath));
     } catch (FormatError & e) {
-        throw Error(format("error parsing derivation '%1%': %2%") % drvPath % e.msg());
+        throw Error(format("error parsing derivation ‘%1%’: %2%") % drvPath % e.msg());
     }
 }
 
@@ -220,7 +220,7 @@ Derivation Store::derivationFromPath(const Path & drvPath)
     try {
         return parseDerivation(accessor->readFile(drvPath));
     } catch (FormatError & e) {
-        throw Error(format("error parsing derivation '%1%': %2%") % drvPath % e.msg());
+        throw Error(format("error parsing derivation ‘%1%’: %2%") % drvPath % e.msg());
     }
 }
 
diff --git a/src/libstore/download.cc b/src/libstore/download.cc
index 8682d244ffad41053dcca0118841c78a972afa54..954044c2344fd55f09aa07d9be62671191af6c83 100644
--- a/src/libstore/download.cc
+++ b/src/libstore/download.cc
@@ -87,7 +87,7 @@ struct CurlDownloader : public Downloader
             if (requestHeaders) curl_slist_free_all(requestHeaders);
             try {
                 if (!done)
-                    fail(DownloadError(Interrupted, format("download of '%s' was interrupted") % request.uri));
+                    fail(DownloadError(Interrupted, format("download of ‘%s’ was interrupted") % request.uri));
             } catch (...) {
                 ignoreException();
             }
@@ -117,7 +117,7 @@ struct CurlDownloader : public Downloader
         {
             size_t realSize = size * nmemb;
             std::string line((char *) contents, realSize);
-            printMsg(lvlVomit, format("got header for '%s': %s") % request.uri % trim(line));
+            printMsg(lvlVomit, format("got header for ‘%s’: %s") % request.uri % trim(line));
             if (line.compare(0, 5, "HTTP/") == 0) { // new response starts
                 result.etag = "";
                 auto ss = tokenizeString<vector<string>>(line, " ");
@@ -176,7 +176,7 @@ struct CurlDownloader : public Downloader
         {
             // FIXME: handle parallel downloads.
             if (showProgress) {
-                std::cerr << (format("downloading '%1%'... ") % request.uri);
+                std::cerr << (format("downloading ‘%1%’... ") % request.uri);
                 std::cerr.flush();
                 startTime = getTime();
             }
@@ -234,7 +234,7 @@ struct CurlDownloader : public Downloader
             if (effectiveUrlCStr)
                 result.effectiveUrl = effectiveUrlCStr;
 
-            debug(format("finished download of '%s'; curl status = %d, HTTP status = %d, body = %d bytes")
+            debug(format("finished download of ‘%s’; curl status = %d, HTTP status = %d, body = %d bytes")
                 % request.uri % code % httpStatus % (result.data ? result.data->size() : 0));
 
             if (code == CURLE_WRITE_ERROR && result.etag == request.expectedETag) {
@@ -261,10 +261,10 @@ struct CurlDownloader : public Downloader
 
                 auto exc =
                     code == CURLE_ABORTED_BY_CALLBACK && _isInterrupted
-                    ? DownloadError(Interrupted, format("download of '%s' was interrupted") % request.uri)
+                    ? DownloadError(Interrupted, format("download of ‘%s’ was interrupted") % request.uri)
                     : httpStatus != 0
-                      ? DownloadError(err, format("unable to download '%s': HTTP error %d") % request.uri % httpStatus)
-                      : DownloadError(err, format("unable to download '%s': %s (%d)") % request.uri % curl_easy_strerror(code) % code);
+                      ? DownloadError(err, format("unable to download ‘%s’: HTTP error %d") % request.uri % httpStatus)
+                      : DownloadError(err, format("unable to download ‘%s’: %s (%d)") % request.uri % curl_easy_strerror(code) % code);
 
                 /* If this is a transient error, then maybe retry the
                    download after a while. */
@@ -534,7 +534,7 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
                     if (effectiveUrl)
                         *effectiveUrl = url_;
                 } else if (!ss[1].empty()) {
-                    debug(format("verifying previous ETag '%1%'") % ss[1]);
+                    debug(format("verifying previous ETag ‘%1%’") % ss[1]);
                     expectedETag = ss[1];
                 }
             }
@@ -582,7 +582,7 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
                 unpackedStorePath = "";
         }
         if (unpackedStorePath.empty()) {
-            printInfo(format("unpacking '%1%'...") % url);
+            printInfo(format("unpacking ‘%1%’...") % url);
             Path tmpDir = createTempDir();
             AutoDelete autoDelete(tmpDir, true);
             // FIXME: this requires GNU tar for decompression.
@@ -594,7 +594,7 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
     }
 
     if (expectedStorePath != "" && storePath != expectedStorePath)
-        throw nix::Error(format("hash mismatch in file downloaded from '%s'") % url);
+        throw nix::Error(format("hash mismatch in file downloaded from ‘%s’") % url);
 
     return storePath;
 }
diff --git a/src/libstore/download.hh b/src/libstore/download.hh
index 6703e013ee72267fc22d687840232fdcffaeb5d3..82b5d641fde9c9bb22bcd845649d9c1f0fec57e6 100644
--- a/src/libstore/download.hh
+++ b/src/libstore/download.hh
@@ -46,7 +46,7 @@ struct Downloader
     DownloadResult download(const DownloadRequest & request);
 
     /* Check if the specified file is already in ~/.cache/nix/tarballs
-       and is more recent than 'tarball-ttl' seconds. Otherwise,
+       and is more recent than ‘tarball-ttl’ seconds. Otherwise,
        use the recorded ETag to verify if the server has a more
        recent version, and if so, download it to the Nix store. */
     Path downloadCached(ref<Store> store, const string & uri, bool unpack, string name = "",
diff --git a/src/libstore/export-import.cc b/src/libstore/export-import.cc
index 1f326d2f09c41e5fc7d827389c571b3bffc562cb..c5618c826c54314cc9e19a1650f11cd15c6f3a09 100644
--- a/src/libstore/export-import.cc
+++ b/src/libstore/export-import.cc
@@ -33,7 +33,7 @@ void Store::exportPaths(const Paths & paths, Sink & sink)
     logger->incExpected(doneLabel, sorted.size());
 
     for (auto & path : sorted) {
-        Activity act(*logger, lvlInfo, format("exporting path '%s'") % path);
+        Activity act(*logger, lvlInfo, format("exporting path ‘%s’") % path);
         sink << 1;
         exportPath(path, sink);
         logger->incProgress(doneLabel);
@@ -55,7 +55,7 @@ void Store::exportPath(const Path & path, Sink & sink)
        Don't complain if the stored hash is zero (unknown). */
     Hash hash = hashAndWriteSink.currentHash();
     if (hash != info->narHash && info->narHash != Hash(info->narHash.type))
-        throw Error(format("hash of path '%1%' has changed from '%2%' to '%3%'!") % path
+        throw Error(format("hash of path ‘%1%’ has changed from ‘%2%’ to ‘%3%’!") % path
             % printHash(info->narHash) % printHash(hash));
 
     hashAndWriteSink << exportMagic << path << info->references << info->deriver << 0;
@@ -88,7 +88,7 @@ Paths Store::importPaths(Source & source, std::shared_ptr<FSAccessor> accessor,
     while (true) {
         unsigned long long n = readLongLong(source);
         if (n == 0) break;
-        if (n != 1) throw Error("input doesn't look like something created by 'nix-store --export'");
+        if (n != 1) throw Error("input doesn't look like something created by ‘nix-store --export’");
 
         /* Extract the NAR from the source. */
         TeeSource tee(source);
@@ -103,7 +103,7 @@ Paths Store::importPaths(Source & source, std::shared_ptr<FSAccessor> accessor,
 
         info.path = readStorePath(*this, source);
 
-        Activity act(*logger, lvlInfo, format("importing path '%s'") % info.path);
+        Activity act(*logger, lvlInfo, format("importing path ‘%s’") % info.path);
 
         info.references = readStorePaths<PathSet>(*this, source);
 
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 8f8c0995523d3b062f96dc0b607a5a97174fc80d..ae03604faf983a76a2af9418d3cdce5bc31d9920 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -32,11 +32,11 @@ int LocalStore::openGCLock(LockType lockType)
     Path fnGCLock = (format("%1%/%2%")
         % stateDir % gcLockName).str();
 
-    debug(format("acquiring global GC lock '%1%'") % fnGCLock);
+    debug(format("acquiring global GC lock ‘%1%’") % fnGCLock);
 
     AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600);
     if (!fdGCLock)
-        throw SysError(format("opening global GC lock '%1%'") % fnGCLock);
+        throw SysError(format("opening global GC lock ‘%1%’") % fnGCLock);
 
     if (!lockFile(fdGCLock.get(), lockType, false)) {
         printError(format("waiting for the big garbage collector lock..."));
@@ -63,7 +63,7 @@ static void makeSymlink(const Path & link, const Path & target)
 
     /* Atomically replace the old one. */
     if (rename(tempLink.c_str(), link.c_str()) == -1)
-        throw SysError(format("cannot rename '%1%' to '%2%'")
+        throw SysError(format("cannot rename ‘%1%’ to ‘%2%’")
             % tempLink % link);
 }
 
@@ -99,7 +99,7 @@ Path LocalFSStore::addPermRoot(const Path & _storePath,
         /* Don't clobber the link if it already exists and doesn't
            point to the Nix store. */
         if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot))))
-            throw Error(format("cannot create symlink '%1%'; already exists") % gcRoot);
+            throw Error(format("cannot create symlink ‘%1%’; already exists") % gcRoot);
         makeSymlink(gcRoot, storePath);
         addIndirectRoot(gcRoot);
     }
@@ -110,8 +110,8 @@ Path LocalFSStore::addPermRoot(const Path & _storePath,
 
             if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/")
                 throw Error(format(
-                    "path '%1%' is not a valid garbage collector root; "
-                    "it's not in the directory '%2%'")
+                    "path ‘%1%’ is not a valid garbage collector root; "
+                    "it's not in the directory ‘%2%’")
                     % gcRoot % rootsDir);
         }
 
@@ -131,8 +131,8 @@ Path LocalFSStore::addPermRoot(const Path & _storePath,
         if (roots.find(gcRoot) == roots.end())
             printError(
                 format(
-                    "warning: '%1%' is not in a directory where the garbage collector looks for roots; "
-                    "therefore, '%2%' might be removed by the garbage collector")
+                    "warning: ‘%1%’ is not in a directory where the garbage collector looks for roots; "
+                    "therefore, ‘%2%’ might be removed by the garbage collector")
                 % gcRoot % storePath);
     }
 
@@ -169,14 +169,14 @@ void LocalStore::addTempRoot(const Path & path)
 
             fdGCLock = -1;
 
-            debug(format("acquiring read lock on '%1%'") % state->fnTempRoots);
+            debug(format("acquiring read lock on ‘%1%’") % state->fnTempRoots);
             lockFile(state->fdTempRoots.get(), ltRead, true);
 
             /* Check whether the garbage collector didn't get in our
                way. */
             struct stat st;
             if (fstat(state->fdTempRoots.get(), &st) == -1)
-                throw SysError(format("statting '%1%'") % state->fnTempRoots);
+                throw SysError(format("statting ‘%1%’") % state->fnTempRoots);
             if (st.st_size == 0) break;
 
             /* The garbage collector deleted this file before we could
@@ -188,14 +188,14 @@ void LocalStore::addTempRoot(const Path & path)
 
     /* Upgrade the lock to a write lock.  This will cause us to block
        if the garbage collector is holding our lock. */
-    debug(format("acquiring write lock on '%1%'") % state->fnTempRoots);
+    debug(format("acquiring write lock on ‘%1%’") % state->fnTempRoots);
     lockFile(state->fdTempRoots.get(), ltWrite, true);
 
     string s = path + '\0';
     writeFull(state->fdTempRoots.get(), s);
 
     /* Downgrade to a read lock. */
-    debug(format("downgrading to read lock on '%1%'") % state->fnTempRoots);
+    debug(format("downgrading to read lock on ‘%1%’") % state->fnTempRoots);
     lockFile(state->fdTempRoots.get(), ltRead, true);
 }
 
@@ -210,12 +210,12 @@ void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
     for (auto & i : tempRootFiles) {
         Path path = (format("%1%/%2%/%3%") % stateDir % tempRootsDir % i.name).str();
 
-        debug(format("reading temporary root file '%1%'") % path);
+        debug(format("reading temporary root file ‘%1%’") % path);
         FDPtr fd(new AutoCloseFD(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666)));
         if (!*fd) {
             /* It's okay if the file has disappeared. */
             if (errno == ENOENT) continue;
-            throw SysError(format("opening temporary roots file '%1%'") % path);
+            throw SysError(format("opening temporary roots file ‘%1%’") % path);
         }
 
         /* This should work, but doesn't, for some reason. */
@@ -226,7 +226,7 @@ void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
            only succeed if the owning process has died.  In that case
            we don't care about its temporary roots. */
         if (lockFile(fd->get(), ltWrite, false)) {
-            printError(format("removing stale temporary roots file '%1%'") % path);
+            printError(format("removing stale temporary roots file ‘%1%’") % path);
             unlink(path.c_str());
             writeFull(fd->get(), "d");
             continue;
@@ -235,7 +235,7 @@ void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
         /* Acquire a read lock.  This will prevent the owning process
            from upgrading to a write lock, therefore it will block in
            addTempRoot(). */
-        debug(format("waiting for read lock on '%1%'") % path);
+        debug(format("waiting for read lock on ‘%1%’") % path);
         lockFile(fd->get(), ltRead, true);
 
         /* Read the entire file. */
@@ -246,7 +246,7 @@ void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
 
         while ((end = contents.find((char) 0, pos)) != string::npos) {
             Path root(contents, pos, end - pos);
-            debug(format("got temporary root '%1%'") % root);
+            debug(format("got temporary root ‘%1%’") % root);
             assertStorePath(root);
             tempRoots.insert(root);
             pos = end + 1;
@@ -264,7 +264,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
         if (isStorePath(storePath) && isValidPath(storePath))
             roots[path] = storePath;
         else
-            printInfo(format("skipping invalid root from '%1%' to '%2%'") % path % storePath);
+            printInfo(format("skipping invalid root from ‘%1%’ to ‘%2%’") % path % storePath);
     };
 
     try {
@@ -287,7 +287,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
                 target = absPath(target, dirOf(path));
                 if (!pathExists(target)) {
                     if (isInDir(path, stateDir + "/" + gcRootsDir + "/auto")) {
-                        printInfo(format("removing stale link from '%1%' to '%2%'") % path % target);
+                        printInfo(format("removing stale link from ‘%1%’ to ‘%2%’") % path % target);
                         unlink(path.c_str());
                     }
                 } else {
@@ -310,7 +310,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
     catch (SysError & e) {
         /* We only ignore permanent failures. */
         if (e.errNo == EACCES || e.errNo == ENOENT || e.errNo == ENOTDIR)
-            printInfo(format("cannot read potential root '%1%'") % path);
+            printInfo(format("cannot read potential root ‘%1%’") % path);
         else
             throw;
     }
@@ -447,7 +447,7 @@ void LocalStore::findRuntimeRoots(PathSet & roots)
         if (isInStore(i)) {
             Path path = toStorePath(i);
             if (roots.find(path) == roots.end() && isStorePath(path) && isValidPath(path)) {
-                debug(format("got additional root '%1%'") % path);
+                debug(format("got additional root ‘%1%’") % path);
                 roots.insert(path);
             }
         }
@@ -513,7 +513,7 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
         throw SysError(format("getting status of %1%") % realPath);
     }
 
-    printInfo(format("deleting '%1%'") % path);
+    printInfo(format("deleting ‘%1%’") % path);
 
     state.results.paths.insert(path);
 
@@ -528,14 +528,14 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
         // size.
         try {
             if (chmod(realPath.c_str(), st.st_mode | S_IWUSR) == -1)
-                throw SysError(format("making '%1%' writable") % realPath);
+                throw SysError(format("making ‘%1%’ writable") % realPath);
             Path tmp = trashDir + "/" + baseNameOf(path);
             if (rename(realPath.c_str(), tmp.c_str()))
-                throw SysError(format("unable to rename '%1%' to '%2%'") % realPath % tmp);
+                throw SysError(format("unable to rename ‘%1%’ to ‘%2%’") % realPath % tmp);
             state.bytesInvalidated += size;
         } catch (SysError & e) {
             if (e.errNo == ENOSPC) {
-                printInfo(format("note: can't create move '%1%': %2%") % realPath % e.msg());
+                printInfo(format("note: can't create move ‘%1%’: %2%") % realPath % e.msg());
                 deleteGarbage(state, realPath);
             }
         }
@@ -562,7 +562,7 @@ bool LocalStore::canReachRoot(GCState & state, PathSet & visited, const Path & p
     }
 
     if (state.roots.find(path) != state.roots.end()) {
-        debug(format("cannot delete '%1%' because it's a root") % path);
+        debug(format("cannot delete ‘%1%’ because it's a root") % path);
         state.alive.insert(path);
         return true;
     }
@@ -611,7 +611,7 @@ void LocalStore::tryToDelete(GCState & state, const Path & path)
     auto realPath = realStoreDir + "/" + baseNameOf(path);
     if (realPath == linksDir || realPath == trashDir) return;
 
-    Activity act(*logger, lvlDebug, format("considering whether to delete '%1%'") % path);
+    Activity act(*logger, lvlDebug, format("considering whether to delete ‘%1%’") % path);
 
     if (!isStorePath(path) || !isValidPath(path)) {
         /* A lock file belonging to a path that we're building right
@@ -626,11 +626,11 @@ void LocalStore::tryToDelete(GCState & state, const Path & path)
     PathSet visited;
 
     if (canReachRoot(state, visited, path)) {
-        debug(format("cannot delete '%1%' because it's still reachable") % path);
+        debug(format("cannot delete ‘%1%’ because it's still reachable") % path);
     } else {
         /* No path we visited was a root, so everything is garbage.
-           But we only delete 'path' and its referrers here so that
-           'nix-store --delete' doesn't have the unexpected effect of
+           But we only delete ‘path’ and its referrers here so that
+           ‘nix-store --delete’ doesn't have the unexpected effect of
            recursing into derivations and outputs. */
         state.dead.insert(visited.begin(), visited.end());
         if (state.shouldDelete)
@@ -647,7 +647,7 @@ void LocalStore::tryToDelete(GCState & state, const Path & path)
 void LocalStore::removeUnusedLinks(const GCState & state)
 {
     AutoCloseDir dir = opendir(linksDir.c_str());
-    if (!dir) throw SysError(format("opening directory '%1%'") % linksDir);
+    if (!dir) throw SysError(format("opening directory ‘%1%’") % linksDir);
 
     long long actualSize = 0, unsharedSize = 0;
 
@@ -660,7 +660,7 @@ void LocalStore::removeUnusedLinks(const GCState & state)
 
         struct stat st;
         if (lstat(path.c_str(), &st) == -1)
-            throw SysError(format("statting '%1%'") % path);
+            throw SysError(format("statting ‘%1%’") % path);
 
         if (st.st_nlink != 1) {
             unsigned long long size = st.st_blocks * 512ULL;
@@ -669,17 +669,17 @@ void LocalStore::removeUnusedLinks(const GCState & state)
             continue;
         }
 
-        printMsg(lvlTalkative, format("deleting unused link '%1%'") % path);
+        printMsg(lvlTalkative, format("deleting unused link ‘%1%’") % path);
 
         if (unlink(path.c_str()) == -1)
-            throw SysError(format("deleting '%1%'") % path);
+            throw SysError(format("deleting ‘%1%’") % path);
 
         state.results.bytesFreed += st.st_blocks * 512;
     }
 
     struct stat st;
     if (stat(linksDir.c_str(), &st) == -1)
-        throw SysError(format("statting '%1%'") % linksDir);
+        throw SysError(format("statting ‘%1%’") % linksDir);
     long long overhead = st.st_blocks * 512ULL;
 
     printInfo(format("note: currently hard linking saves %.2f MiB")
@@ -759,7 +759,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
             assertStorePath(i);
             tryToDelete(state, i);
             if (state.dead.find(i) == state.dead.end())
-                throw Error(format("cannot delete path '%1%' since it is still alive") % i);
+                throw Error(format("cannot delete path ‘%1%’ since it is still alive") % i);
         }
 
     } else if (options.maxFreed > 0) {
@@ -772,7 +772,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
         try {
 
             AutoCloseDir dir = opendir(realStoreDir.c_str());
-            if (!dir) throw SysError(format("opening directory '%1%'") % realStoreDir);
+            if (!dir) throw SysError(format("opening directory ‘%1%’") % realStoreDir);
 
             /* Read the store and immediately delete all paths that
                aren't valid.  When using --max-freed etc., deleting
@@ -825,7 +825,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
     fds.clear();
 
     /* Delete the trash directory. */
-    printInfo(format("deleting '%1%'") % trashDir);
+    printInfo(format("deleting ‘%1%’") % trashDir);
     deleteGarbage(state, trashDir);
 
     /* Clean up the links directory. */
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 84f93ba2852202c44a9d6897eda36ef53daa4223..00b4688925297f6f03ffc01ace436b84ec899d0e 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -103,7 +103,7 @@ void Settings::loadConfFile()
         if (tokens.empty()) continue;
 
         if (tokens.size() < 2 || tokens[1] != "=")
-            throw Error(format("illegal configuration line '%1%' in '%2%'") % line % settingsFile);
+            throw Error(format("illegal configuration line ‘%1%’ in ‘%2%’") % line % settingsFile);
 
         string name = tokens[0];
 
@@ -202,7 +202,7 @@ void Settings::_get(bool & res, const string & name)
     if (i == settings.end()) return;
     if (i->second == "true") res = true;
     else if (i->second == "false") res = false;
-    else throw Error(format("configuration option '%1%' should be either 'true' or 'false', not '%2%'")
+    else throw Error(format("configuration option ‘%1%’ should be either ‘true’ or ‘false’, not ‘%2%’")
         % name % i->second);
 }
 
@@ -229,7 +229,7 @@ template<class N> void Settings::_get(N & res, const string & name)
     SettingsMap::iterator i = settings.find(name);
     if (i == settings.end()) return;
     if (!string2Int(i->second, res))
-        throw Error(format("configuration setting '%1%' should have an integer value") % name);
+        throw Error(format("configuration setting ‘%1%’ should have an integer value") % name);
 }
 
 
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 0e34b08de5a7c8fceb28f65a460aeee60f47dd1a..9d31f77c921f8f60a04636d817fe0cc66287d82a 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -38,7 +38,7 @@ public:
             try {
                 BinaryCacheStore::init();
             } catch (UploadToHTTP &) {
-                throw Error(format("'%s' does not appear to be a binary cache") % cacheUri);
+                throw Error(format("‘%s’ does not appear to be a binary cache") % cacheUri);
             }
             diskCache->createCache(cacheUri, storeDir, wantMassQuery_, priority);
         }
diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc
index bce4dfd5e23472b6643adf20deb513ecae6166f2..0f377989bd892e8d80b7d8fddd395f073868ce32 100644
--- a/src/libstore/local-binary-cache-store.cc
+++ b/src/libstore/local-binary-cache-store.cc
@@ -74,7 +74,7 @@ static void atomicWrite(const Path & path, const std::string & s)
     AutoDelete del(tmp, false);
     writeFile(tmp, s);
     if (rename(tmp.c_str(), path.c_str()))
-        throw SysError(format("renaming '%1%' to '%2%'") % tmp % path);
+        throw SysError(format("renaming ‘%1%’ to ‘%2%’") % tmp % path);
     del.cancel();
 }
 
diff --git a/src/libstore/local-fs-store.cc b/src/libstore/local-fs-store.cc
index 6c3e51d06fb76cac7e18198103e42c9377116e22..4571a2211cd275e9e7c7d9f30a2098ddf54051a2 100644
--- a/src/libstore/local-fs-store.cc
+++ b/src/libstore/local-fs-store.cc
@@ -23,7 +23,7 @@ struct LocalStoreAccessor : public FSAccessor
     {
         Path storePath = store->toStorePath(path);
         if (!store->isValidPath(storePath))
-            throw InvalidPath(format("path '%1%' is not a valid store path") % storePath);
+            throw InvalidPath(format("path ‘%1%’ is not a valid store path") % storePath);
         return store->getRealStoreDir() + std::string(path, store->storeDir.size());
     }
 
@@ -34,11 +34,11 @@ struct LocalStoreAccessor : public FSAccessor
         struct stat st;
         if (lstat(path.c_str(), &st)) {
             if (errno == ENOENT || errno == ENOTDIR) return {Type::tMissing, 0, false};
-            throw SysError(format("getting status of '%1%'") % path);
+            throw SysError(format("getting status of ‘%1%’") % path);
         }
 
         if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode))
-            throw Error(format("file '%1%' has unsupported type") % path);
+            throw Error(format("file ‘%1%’ has unsupported type") % path);
 
         return {
             S_ISREG(st.st_mode) ? Type::tRegular :
@@ -80,7 +80,7 @@ ref<FSAccessor> LocalFSStore::getFSAccessor()
 void LocalFSStore::narFromPath(const Path & path, Sink & sink)
 {
     if (!isValidPath(path))
-        throw Error(format("path '%s' is not valid") % path);
+        throw Error(format("path ‘%s’ is not valid") % path);
     dumpPath(getRealStoreDir() + std::string(path, storeDir.size()), sink);
 }
 
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index a9e31dc1237b943e523cf68f4b7dcd3f56fa2af6..612efde7bb8fb084e15c203b9924ff377186e206 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -71,24 +71,24 @@ LocalStore::LocalStore(const Params & params)
         Path perUserDir = profilesDir + "/per-user";
         createDirs(perUserDir);
         if (chmod(perUserDir.c_str(), 01777) == -1)
-            throw SysError(format("could not set permissions on '%1%' to 1777") % perUserDir);
+            throw SysError(format("could not set permissions on ‘%1%’ to 1777") % perUserDir);
 
         mode_t perm = 01775;
 
         struct group * gr = getgrnam(settings.buildUsersGroup.c_str());
         if (!gr)
-            printError(format("warning: the group '%1%' specified in 'build-users-group' does not exist")
+            printError(format("warning: the group ‘%1%’ specified in ‘build-users-group’ does not exist")
                 % settings.buildUsersGroup);
         else {
             struct stat st;
             if (stat(realStoreDir.c_str(), &st))
-                throw SysError(format("getting attributes of path '%1%'") % realStoreDir);
+                throw SysError(format("getting attributes of path ‘%1%’") % realStoreDir);
 
             if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) {
                 if (chown(realStoreDir.c_str(), 0, gr->gr_gid) == -1)
-                    throw SysError(format("changing ownership of path '%1%'") % realStoreDir);
+                    throw SysError(format("changing ownership of path ‘%1%’") % realStoreDir);
                 if (chmod(realStoreDir.c_str(), perm) == -1)
-                    throw SysError(format("changing permissions on path '%1%'") % realStoreDir);
+                    throw SysError(format("changing permissions on path ‘%1%’") % realStoreDir);
             }
         }
     }
@@ -99,10 +99,10 @@ LocalStore::LocalStore(const Params & params)
         struct stat st;
         while (path != "/") {
             if (lstat(path.c_str(), &st))
-                throw SysError(format("getting status of '%1%'") % path);
+                throw SysError(format("getting status of ‘%1%’") % path);
             if (S_ISLNK(st.st_mode))
                 throw Error(format(
-                        "the path '%1%' is a symlink; "
+                        "the path ‘%1%’ is a symlink; "
                         "this is not allowed for the Nix store and its parent directories")
                     % path);
             path = dirOf(path);
@@ -262,7 +262,7 @@ int LocalStore::getSchema()
     if (pathExists(schemaPath)) {
         string s = readFile(schemaPath);
         if (!string2Int(s, curSchema))
-            throw Error(format("'%1%' is corrupt") % schemaPath);
+            throw Error(format("‘%1%’ is corrupt") % schemaPath);
     }
     return curSchema;
 }
@@ -271,14 +271,14 @@ int LocalStore::getSchema()
 void LocalStore::openDB(State & state, bool create)
 {
     if (access(dbDir.c_str(), R_OK | W_OK))
-        throw SysError(format("Nix database directory '%1%' is not writable") % dbDir);
+        throw SysError(format("Nix database directory ‘%1%’ is not writable") % dbDir);
 
     /* Open the Nix database. */
     string dbPath = dbDir + "/db.sqlite";
     auto & db(state.db);
     if (sqlite3_open_v2(dbPath.c_str(), &db.db,
             SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK)
-        throw Error(format("cannot open Nix database '%1%'") % dbPath);
+        throw Error(format("cannot open Nix database ‘%1%’") % dbPath);
 
     if (sqlite3_busy_timeout(db, 60 * 60 * 1000) != SQLITE_OK)
         throwSQLiteError(db, "setting timeout");
@@ -363,7 +363,7 @@ static void canonicaliseTimestampAndPermissions(const Path & path, const struct
                  | 0444
                  | (st.st_mode & S_IXUSR ? 0111 : 0);
             if (chmod(path.c_str(), mode) == -1)
-                throw SysError(format("changing mode of '%1%' to %2$o") % path % mode);
+                throw SysError(format("changing mode of ‘%1%’ to %2$o") % path % mode);
         }
 
     }
@@ -381,7 +381,7 @@ static void canonicaliseTimestampAndPermissions(const Path & path, const struct
 #else
         if (!S_ISLNK(st.st_mode) && utimes(path.c_str(), times) == -1)
 #endif
-            throw SysError(format("changing modification time of '%1%'") % path);
+            throw SysError(format("changing modification time of ‘%1%’") % path);
     }
 }
 
@@ -390,7 +390,7 @@ void canonicaliseTimestampAndPermissions(const Path & path)
 {
     struct stat st;
     if (lstat(path.c_str(), &st))
-        throw SysError(format("getting attributes of path '%1%'") % path);
+        throw SysError(format("getting attributes of path ‘%1%’") % path);
     canonicaliseTimestampAndPermissions(path, st);
 }
 
@@ -401,11 +401,11 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
 
     struct stat st;
     if (lstat(path.c_str(), &st))
-        throw SysError(format("getting attributes of path '%1%'") % path);
+        throw SysError(format("getting attributes of path ‘%1%’") % path);
 
     /* Really make sure that the path is of a supported type. */
     if (!(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)))
-        throw Error(format("file '%1%' has an unsupported type") % path);
+        throw Error(format("file ‘%1%’ has an unsupported type") % path);
 
     /* Fail if the file is not owned by the build user.  This prevents
        us from messing up the ownership/permissions of files
@@ -416,7 +416,7 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
     if (fromUid != (uid_t) -1 && st.st_uid != fromUid) {
         assert(!S_ISDIR(st.st_mode));
         if (inodesSeen.find(Inode(st.st_dev, st.st_ino)) == inodesSeen.end())
-            throw BuildError(format("invalid ownership on file '%1%'") % path);
+            throw BuildError(format("invalid ownership on file ‘%1%’") % path);
         mode_t mode = st.st_mode & ~S_IFMT;
         assert(S_ISLNK(st.st_mode) || (st.st_uid == geteuid() && (mode == 0444 || mode == 0555) && st.st_mtime == mtimeStore));
         return;
@@ -440,7 +440,7 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
         if (!S_ISLNK(st.st_mode) &&
             chown(path.c_str(), geteuid(), getegid()) == -1)
 #endif
-            throw SysError(format("changing owner of '%1%' to %2%")
+            throw SysError(format("changing owner of ‘%1%’ to %2%")
                 % path % geteuid());
     }
 
@@ -460,11 +460,11 @@ void canonicalisePathMetaData(const Path & path, uid_t fromUid, InodesSeen & ino
        be a symlink, since we can't change its ownership. */
     struct stat st;
     if (lstat(path.c_str(), &st))
-        throw SysError(format("getting attributes of path '%1%'") % path);
+        throw SysError(format("getting attributes of path ‘%1%’") % path);
 
     if (st.st_uid != geteuid()) {
         assert(S_ISLNK(st.st_mode));
-        throw Error(format("wrong ownership of top-level store path '%1%'") % path);
+        throw Error(format("wrong ownership of top-level store path ‘%1%’") % path);
     }
 }
 
@@ -485,7 +485,7 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
     if (drv.isFixedOutput()) {
         DerivationOutputs::const_iterator out = drv.outputs.find("out");
         if (out == drv.outputs.end())
-            throw Error(format("derivation '%1%' does not have an output named 'out'") % drvPath);
+            throw Error(format("derivation ‘%1%’ does not have an output named ‘out’") % drvPath);
 
         bool recursive; Hash h;
         out->second.parseHashInfo(recursive, h);
@@ -493,7 +493,7 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
 
         StringPairs::const_iterator j = drv.env.find("out");
         if (out->second.path != outPath || j == drv.env.end() || j->second != outPath)
-            throw Error(format("derivation '%1%' has incorrect output '%2%', should be '%3%'")
+            throw Error(format("derivation ‘%1%’ has incorrect output ‘%2%’, should be ‘%3%’")
                 % drvPath % out->second.path % outPath);
     }
 
@@ -510,7 +510,7 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
             Path outPath = makeOutputPath(i.first, h, drvName);
             StringPairs::const_iterator j = drv.env.find(i.first);
             if (i.second.path != outPath || j == drv.env.end() || j->second != outPath)
-                throw Error(format("derivation '%1%' has incorrect output '%2%', should be '%3%'")
+                throw Error(format("derivation ‘%1%’ has incorrect output ‘%2%’, should be ‘%3%’")
                     % drvPath % i.second.path % outPath);
         }
     }
@@ -568,11 +568,11 @@ Hash parseHashField(const Path & path, const string & s)
 {
     string::size_type colon = s.find(':');
     if (colon == string::npos)
-        throw Error(format("corrupt hash '%1%' in valid-path entry for '%2%'")
+        throw Error(format("corrupt hash ‘%1%’ in valid-path entry for ‘%2%’")
             % s % path);
     HashType ht = parseHashType(string(s, 0, colon));
     if (ht == htUnknown)
-        throw Error(format("unknown hash type '%1%' in valid-path entry for '%2%'")
+        throw Error(format("unknown hash type ‘%1%’ in valid-path entry for ‘%2%’")
             % string(s, 0, colon) % path);
     return parseHash(ht, string(s, colon + 1));
 }
@@ -648,7 +648,7 @@ uint64_t LocalStore::queryValidPathId(State & state, const Path & path)
 {
     auto use(state.stmtQueryPathInfo.use()(path));
     if (!use.next())
-        throw Error(format("path '%1%' is not valid") % path);
+        throw Error(format("path ‘%1%’ is not valid") % path);
     return use.getInt(0);
 }
 
@@ -815,7 +815,7 @@ void LocalStore::querySubstitutablePathInfos(const PathSet & paths,
         if (sub->storeDir != storeDir) continue;
         for (auto & path : paths) {
             if (infos.count(path)) continue;
-            debug(format("checking substituter '%s' for path '%s'")
+            debug(format("checking substituter ‘%s’ for path ‘%s’")
                 % sub->getUri() % path);
             try {
                 auto info = sub->queryPathInfo(path);
@@ -896,7 +896,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
    there are no referrers. */
 void LocalStore::invalidatePath(State & state, const Path & path)
 {
-    debug(format("invalidating path '%1%'") % path);
+    debug(format("invalidating path ‘%1%’") % path);
 
     state.stmtInvalidatePath.use()(path).exec();
 
@@ -915,11 +915,11 @@ void LocalStore::addToStore(const ValidPathInfo & info, const ref<std::string> &
 {
     Hash h = hashString(htSHA256, *nar);
     if (h != info.narHash)
-        throw Error(format("hash mismatch importing path '%s'; expected hash '%s', got '%s'") %
+        throw Error(format("hash mismatch importing path ‘%s’; expected hash ‘%s’, got ‘%s’") %
             info.path % info.narHash.to_string() % h.to_string());
 
     if (requireSigs && !dontCheckSigs && !info.checkSignatures(*this, publicKeys))
-        throw Error(format("cannot import path '%s' because it lacks a valid signature") % info.path);
+        throw Error(format("cannot import path ‘%s’ because it lacks a valid signature") % info.path);
 
     addTempRoot(info.path);
 
@@ -1106,7 +1106,7 @@ void LocalStore::invalidatePathChecked(const Path & path)
             PathSet referrers; queryReferrers(*state, path, referrers);
             referrers.erase(path); /* ignore self-references */
             if (!referrers.empty())
-                throw PathInUse(format("cannot delete path '%1%' because it is in use by %2%")
+                throw PathInUse(format("cannot delete path ‘%1%’ because it is in use by %2%")
                     % path % showPaths(referrers));
             invalidatePath(*state, path);
         }
@@ -1151,12 +1151,12 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
                 auto info = std::const_pointer_cast<ValidPathInfo>(std::shared_ptr<const ValidPathInfo>(queryPathInfo(i)));
 
                 /* Check the content hash (optionally - slow). */
-                printMsg(lvlTalkative, format("checking contents of '%1%'") % i);
+                printMsg(lvlTalkative, format("checking contents of ‘%1%’") % i);
                 HashResult current = hashPath(info->narHash.type, i);
 
                 if (info->narHash != nullHash && info->narHash != current.first) {
-                    printError(format("path '%1%' was modified! "
-                            "expected hash '%2%', got '%3%'")
+                    printError(format("path ‘%1%’ was modified! "
+                            "expected hash ‘%2%’, got ‘%3%’")
                         % i % printHash(info->narHash) % printHash(current.first));
                     if (repair) repairPath(i); else errors = true;
                 } else {
@@ -1165,14 +1165,14 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
 
                     /* Fill in missing hashes. */
                     if (info->narHash == nullHash) {
-                        printError(format("fixing missing hash on '%1%'") % i);
+                        printError(format("fixing missing hash on ‘%1%’") % i);
                         info->narHash = current.first;
                         update = true;
                     }
 
                     /* Fill in missing narSize fields (from old stores). */
                     if (info->narSize == 0) {
-                        printError(format("updating size field on '%1%' to %2%") % i % current.second);
+                        printError(format("updating size field on ‘%1%’ to %2%") % i % current.second);
                         info->narSize = current.second;
                         update = true;
                     }
@@ -1209,7 +1209,7 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
     done.insert(path);
 
     if (!isStorePath(path)) {
-        printError(format("path '%1%' is not in the Nix store") % path);
+        printError(format("path ‘%1%’ is not in the Nix store") % path);
         auto state(_state.lock());
         invalidatePath(*state, path);
         return;
@@ -1228,11 +1228,11 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
             }
 
         if (canInvalidate) {
-            printError(format("path '%1%' disappeared, removing from database...") % path);
+            printError(format("path ‘%1%’ disappeared, removing from database...") % path);
             auto state(_state.lock());
             invalidatePath(*state, path);
         } else {
-            printError(format("path '%1%' disappeared, but it still has valid referrers!") % path);
+            printError(format("path ‘%1%’ disappeared, but it still has valid referrers!") % path);
             if (repair)
                 try {
                     repairPath(path);
@@ -1271,7 +1271,7 @@ static void makeMutable(const Path & path)
     AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
     if (fd == -1) {
         if (errno == ELOOP) return; // it's a symlink
-        throw SysError(format("opening file '%1%'") % path);
+        throw SysError(format("opening file ‘%1%’") % path);
     }
 
     unsigned int flags = 0, old;
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 42b02ce461e32f2faad45331a8bddcf9e94b7e2a..511209d8404a9ff363bbb6d521b911aa67bf4d15 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -261,7 +261,7 @@ private:
     void queryReferrers(State & state, const Path & path, PathSet & referrers);
 
     /* Add signatures to a ValidPathInfo using the secret keys
-       specified by the 'secret-key-files' option. */
+       specified by the ‘secret-key-files’ option. */
     void signPathInfo(ValidPathInfo & info);
 
     Path getRealStoreDir() override { return realStoreDir; }
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc
index 8fa84d3a27874e20048f615ef62d5c373a5d8068..9a88cdc317b62f8ab10372f93da4caa29a2d3fd6 100644
--- a/src/libstore/misc.cc
+++ b/src/libstore/misc.cc
@@ -245,7 +245,7 @@ Paths Store::topoSortPaths(const PathSet & paths)
 
     dfsVisit = [&](const Path & path, const Path * parent) {
         if (parents.find(path) != parents.end())
-            throw BuildError(format("cycle detected in the references of '%1%' from '%2%'") % path % *parent);
+            throw BuildError(format("cycle detected in the references of ‘%1%’ from ‘%2%’") % path % *parent);
 
         if (visited.find(path) != visited.end()) return;
         visited.insert(path);
diff --git a/src/libstore/nar-accessor.cc b/src/libstore/nar-accessor.cc
index 686ecd727c4713cf3c9a1945b7b1009559f50fb6..ded19c05d2cddbb1686155c375803e73f0f01d96 100644
--- a/src/libstore/nar-accessor.cc
+++ b/src/libstore/nar-accessor.cc
@@ -75,7 +75,7 @@ struct NarIndexer : ParseSink, StringSource
     {
         auto i = members.find(path);
         if (i == members.end())
-            throw Error(format("NAR file does not contain path '%1%'") % path);
+            throw Error(format("NAR file does not contain path ‘%1%’") % path);
         return i;
     }
 };
@@ -103,7 +103,7 @@ struct NarAccessor : public FSAccessor
         auto i = indexer.find(path);
 
         if (i->second.type != FSAccessor::Type::tDirectory)
-            throw Error(format("path '%1%' inside NAR file is not a directory") % path);
+            throw Error(format("path ‘%1%’ inside NAR file is not a directory") % path);
 
         ++i;
         StringSet res;
@@ -120,7 +120,7 @@ struct NarAccessor : public FSAccessor
     {
         auto i = indexer.find(path);
         if (i->second.type != FSAccessor::Type::tRegular)
-            throw Error(format("path '%1%' inside NAR file is not a regular file") % path);
+            throw Error(format("path ‘%1%’ inside NAR file is not a regular file") % path);
         return std::string(*nar, i->second.start, i->second.size);
     }
 
@@ -128,7 +128,7 @@ struct NarAccessor : public FSAccessor
     {
         auto i = indexer.find(path);
         if (i->second.type != FSAccessor::Type::tSymlink)
-            throw Error(format("path '%1%' inside NAR file is not a symlink") % path);
+            throw Error(format("path ‘%1%’ inside NAR file is not a symlink") % path);
         return i->second.target;
     }
 };
diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc
index 0bd28533c2418c3f3ceb32f7ee8a1838167c0794..201cac671a55d295c3ac7460a4da284bc36ac081 100644
--- a/src/libstore/nar-info.cc
+++ b/src/libstore/nar-info.cc
@@ -6,7 +6,7 @@ namespace nix {
 NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & whence)
 {
     auto corrupt = [&]() {
-        throw Error(format("NAR info file '%1%' is corrupt") % whence);
+        throw Error(format("NAR info file ‘%1%’ is corrupt") % whence);
     };
 
     auto parseHashField = [&](const string & s) {
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index cce3b53d48ed487bacaae20fdb8b5f5987a54fb1..454c8b49d84b54cd4d5e105d39d3f65c820cac50 100644
--- a/src/libstore/optimise-store.cc
+++ b/src/libstore/optimise-store.cc
@@ -20,9 +20,9 @@ static void makeWritable(const Path & path)
 {
     struct stat st;
     if (lstat(path.c_str(), &st))
-        throw SysError(format("getting attributes of path '%1%'") % path);
+        throw SysError(format("getting attributes of path ‘%1%’") % path);
     if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
-        throw SysError(format("changing writability of '%1%'") % path);
+        throw SysError(format("changing writability of ‘%1%’") % path);
 }
 
 
@@ -48,7 +48,7 @@ LocalStore::InodeHash LocalStore::loadInodeHash()
     InodeHash inodeHash;
 
     AutoCloseDir dir = opendir(linksDir.c_str());
-    if (!dir) throw SysError(format("opening directory '%1%'") % linksDir);
+    if (!dir) throw SysError(format("opening directory ‘%1%’") % linksDir);
 
     struct dirent * dirent;
     while (errno = 0, dirent = readdir(dir)) { /* sic */
@@ -56,7 +56,7 @@ LocalStore::InodeHash LocalStore::loadInodeHash()
         // We don't care if we hit non-hash files, anything goes
         inodeHash.insert(dirent->d_ino);
     }
-    if (errno) throw SysError(format("reading directory '%1%'") % linksDir);
+    if (errno) throw SysError(format("reading directory ‘%1%’") % linksDir);
 
     printMsg(lvlTalkative, format("loaded %1% hash inodes") % inodeHash.size());
 
@@ -69,14 +69,14 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa
     Strings names;
 
     AutoCloseDir dir = opendir(path.c_str());
-    if (!dir) throw SysError(format("opening directory '%1%'") % path);
+    if (!dir) throw SysError(format("opening directory ‘%1%’") % path);
 
     struct dirent * dirent;
     while (errno = 0, dirent = readdir(dir)) { /* sic */
         checkInterrupt();
 
         if (inodeHash.count(dirent->d_ino)) {
-            debug(format("'%1%' is already linked") % dirent->d_name);
+            debug(format("‘%1%’ is already linked") % dirent->d_name);
             continue;
         }
 
@@ -84,7 +84,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa
         if (name == "." || name == "..") continue;
         names.push_back(name);
     }
-    if (errno) throw SysError(format("reading directory '%1%'") % path);
+    if (errno) throw SysError(format("reading directory ‘%1%’") % path);
 
     return names;
 }
@@ -96,7 +96,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
 
     struct stat st;
     if (lstat(path.c_str(), &st))
-        throw SysError(format("getting attributes of path '%1%'") % path);
+        throw SysError(format("getting attributes of path ‘%1%’") % path);
 
     if (S_ISDIR(st.st_mode)) {
         Strings names = readDirectoryIgnoringInodes(path, inodeHash);
@@ -117,13 +117,13 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
        NixOS (example: $fontconfig/var/cache being modified).  Skip
        those files.  FIXME: check the modification time. */
     if (S_ISREG(st.st_mode) && (st.st_mode & S_IWUSR)) {
-        printError(format("skipping suspicious writable file '%1%'") % path);
+        printError(format("skipping suspicious writable file ‘%1%’") % path);
         return;
     }
 
     /* This can still happen on top-level files. */
     if (st.st_nlink > 1 && inodeHash.count(st.st_ino)) {
-        debug(format("'%1%' is already linked, with %2% other file(s)") % path % (st.st_nlink - 2));
+        debug(format("‘%1%’ is already linked, with %2% other file(s)") % path % (st.st_nlink - 2));
         return;
     }
 
@@ -137,7 +137,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
        contents of the symlink (i.e. the result of readlink()), not
        the contents of the target (which may not even exist). */
     Hash hash = hashPath(htSHA256, path).first;
-    debug(format("'%1%' has hash '%2%'") % path % printHash(hash));
+    debug(format("‘%1%’ has hash ‘%2%’") % path % printHash(hash));
 
     /* Check if this is a known hash. */
     Path linkPath = linksDir + "/" + printHash32(hash);
@@ -152,7 +152,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
 
         switch (errno) {
         case EEXIST:
-            /* Fall through if another process created 'linkPath' before
+            /* Fall through if another process created ‘linkPath’ before
                we did. */
             break;
 
@@ -161,11 +161,11 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
                full.  When that happens, it's fine to ignore it: we
                just effectively disable deduplication of this
                file.  */
-            printInfo("cannot link '%s' to '%s': %s", linkPath, path, strerror(errno));
+            printInfo("cannot link ‘%s’ to ‘%s’: %s", linkPath, path, strerror(errno));
             return;
 
         default:
-            throw SysError("cannot link '%1%' to '%2%'", linkPath, path);
+            throw SysError("cannot link ‘%1%’ to ‘%2%’", linkPath, path);
         }
     }
 
@@ -173,20 +173,20 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
        current file with a hard link to that file. */
     struct stat stLink;
     if (lstat(linkPath.c_str(), &stLink))
-        throw SysError(format("getting attributes of path '%1%'") % linkPath);
+        throw SysError(format("getting attributes of path ‘%1%’") % linkPath);
 
     if (st.st_ino == stLink.st_ino) {
-        debug(format("'%1%' is already linked to '%2%'") % path % linkPath);
+        debug(format("‘%1%’ is already linked to ‘%2%’") % path % linkPath);
         return;
     }
 
     if (st.st_size != stLink.st_size) {
-        printError(format("removing corrupted link '%1%'") % linkPath);
+        printError(format("removing corrupted link ‘%1%’") % linkPath);
         unlink(linkPath.c_str());
         goto retry;
     }
 
-    printMsg(lvlTalkative, format("linking '%1%' to '%2%'") % path % linkPath);
+    printMsg(lvlTalkative, format("linking ‘%1%’ to ‘%2%’") % path % linkPath);
 
     /* Make the containing directory writable, but only if it's not
        the store itself (we don't want or need to mess with its
@@ -207,26 +207,26 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
                systems).  This is likely to happen with empty files.
                Just shrug and ignore. */
             if (st.st_size)
-                printInfo(format("'%1%' has maximum number of links") % linkPath);
+                printInfo(format("‘%1%’ has maximum number of links") % linkPath);
             return;
         }
-        throw SysError("cannot link '%1%' to '%2%'", tempLink, linkPath);
+        throw SysError("cannot link ‘%1%’ to ‘%2%’", tempLink, linkPath);
     }
 
     /* Atomically replace the old file with the new hard link. */
     if (rename(tempLink.c_str(), path.c_str()) == -1) {
         if (unlink(tempLink.c_str()) == -1)
-            printError(format("unable to unlink '%1%'") % tempLink);
+            printError(format("unable to unlink ‘%1%’") % tempLink);
         if (errno == EMLINK) {
             /* Some filesystems generate too many links on the rename,
                rather than on the original link.  (Probably it
                temporarily increases the st_nlink field before
                decreasing it again.) */
             if (st.st_size)
-                printInfo(format("'%1%' has maximum number of links") % linkPath);
+                printInfo(format("‘%1%’ has maximum number of links") % linkPath);
             return;
         }
-        throw SysError(format("cannot rename '%1%' to '%2%'") % tempLink % path);
+        throw SysError(format("cannot rename ‘%1%’ to ‘%2%’") % tempLink % path);
     }
 
     stats.filesLinked++;
@@ -243,7 +243,7 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
     for (auto & i : paths) {
         addTempRoot(i);
         if (!isValidPath(i)) continue; /* path was GC'ed, probably */
-        Activity act(*logger, lvlChatty, format("hashing files in '%1%'") % i);
+        Activity act(*logger, lvlChatty, format("hashing files in ‘%1%’") % i);
         optimisePath_(stats, realStoreDir + "/" + baseNameOf(i), inodeHash);
     }
 }
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index b473c837a4cafc3a77306554e51b8a0fb3a472d2..8788ee1649fb283f4d7579b877b3fc8453f851af 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -18,7 +18,7 @@ int openLockFile(const Path & path, bool create)
 
     fd = open(path.c_str(), O_CLOEXEC | O_RDWR | (create ? O_CREAT : 0), 0600);
     if (!fd && (create || errno != ENOENT))
-        throw SysError(format("opening lock file '%1%'") % path);
+        throw SysError(format("opening lock file ‘%1%’") % path);
 
     return fd.release();
 }
@@ -106,7 +106,7 @@ bool PathLocks::lockPaths(const PathSet & _paths,
         checkInterrupt();
         Path lockPath = path + ".lock";
 
-        debug(format("locking path '%1%'") % path);
+        debug(format("locking path ‘%1%’") % path);
 
         if (lockedPaths.find(lockPath) != lockedPaths.end())
             throw Error("deadlock: trying to re-acquire self-held lock");
@@ -131,19 +131,19 @@ bool PathLocks::lockPaths(const PathSet & _paths,
                 }
             }
 
-            debug(format("lock acquired on '%1%'") % lockPath);
+            debug(format("lock acquired on ‘%1%’") % lockPath);
 
             /* Check that the lock file hasn't become stale (i.e.,
                hasn't been unlinked). */
             struct stat st;
             if (fstat(fd.get(), &st) == -1)
-                throw SysError(format("statting lock file '%1%'") % lockPath);
+                throw SysError(format("statting lock file ‘%1%’") % lockPath);
             if (st.st_size != 0)
                 /* This lock file has been unlinked, so we're holding
                    a lock on a deleted file.  This means that other
                    processes may create and acquire a lock on
                    `lockPath', and proceed.  So we must retry. */
-                debug(format("open lock file '%1%' has become stale") % lockPath);
+                debug(format("open lock file ‘%1%’ has become stale") % lockPath);
             else
                 break;
         }
@@ -175,9 +175,9 @@ void PathLocks::unlock()
         lockedPaths.erase(i.second);
         if (close(i.first) == -1)
             printError(
-                format("error (ignored): cannot close lock file on '%1%'") % i.second);
+                format("error (ignored): cannot close lock file on ‘%1%’") % i.second);
 
-        debug(format("lock released on '%1%'") % i.second);
+        debug(format("lock released on ‘%1%’") % i.second);
     }
 
     fds.clear();
diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc
index 4a607b584506d54b2794fe1a42f3874fe9558182..f24daa8862a1d90fdcf3b621717484fe17c46f50 100644
--- a/src/libstore/profiles.cc
+++ b/src/libstore/profiles.cc
@@ -50,7 +50,7 @@ Generations findGenerations(Path profile, int & curGen)
             gen.number = n;
             struct stat st;
             if (lstat(gen.path.c_str(), &st) != 0)
-                throw SysError(format("statting '%1%'") % gen.path);
+                throw SysError(format("statting ‘%1%’") % gen.path);
             gen.creationTime = st.st_mtime;
             gens.push_back(gen);
         }
@@ -117,7 +117,7 @@ Path createGeneration(ref<LocalFSStore> store, Path profile, Path outPath)
 static void removeFile(const Path & path)
 {
     if (remove(path.c_str()) == -1)
-        throw SysError(format("cannot unlink '%1%'") % path);
+        throw SysError(format("cannot unlink ‘%1%’") % path);
 }
 
 
@@ -149,7 +149,7 @@ void deleteGenerations(const Path & profile, const std::set<unsigned int> & gens
     Generations gens = findGenerations(profile, curGen);
 
     if (gensToDelete.find(curGen) != gensToDelete.end())
-        throw Error(format("cannot delete current generation of profile %1%'") % profile);
+        throw Error(format("cannot delete current generation of profile %1%’") % profile);
 
     for (auto & i : gens) {
         if (gensToDelete.find(i.number) == gensToDelete.end()) continue;
@@ -203,7 +203,7 @@ void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, b
     int days;
 
     if (!string2Int(strDays, days) || days < 1)
-        throw Error(format("invalid number of days specifier '%1%'") % timeSpec);
+        throw Error(format("invalid number of days specifier ‘%1%’") % timeSpec);
 
     time_t oldTime = curTime - days * 24 * 3600;
 
@@ -222,7 +222,7 @@ void switchLink(Path link, Path target)
 
 void lockProfile(PathLocks & lock, const Path & profile)
 {
-    lock.lockPaths({profile}, (format("waiting for lock on profile '%1%'") % profile).str());
+    lock.lockPaths({profile}, (format("waiting for lock on profile ‘%1%’") % profile).str());
     lock.setDeletion(true);
 }
 
diff --git a/src/libstore/references.cc b/src/libstore/references.cc
index ba9f18b9ca5e5524fe907b7ad0f691be05a8c9a8..33eab5a240b51f1d128573e0678a8bb53adcd4ca 100644
--- a/src/libstore/references.cc
+++ b/src/libstore/references.cc
@@ -37,7 +37,7 @@ static void search(const unsigned char * s, unsigned int len,
         if (!match) continue;
         string ref((const char *) s + i, refLength);
         if (hashes.find(ref) != hashes.end()) {
-            debug(format("found reference to '%1%' at offset '%2%'")
+            debug(format("found reference to ‘%1%’ at offset ‘%2%’")
                   % ref % i);
             seen.insert(ref);
             hashes.erase(ref);
@@ -93,7 +93,7 @@ PathSet scanForReferences(const string & path,
         string baseName = baseNameOf(i);
         string::size_type pos = baseName.find('-');
         if (pos == string::npos)
-            throw Error(format("bad reference '%1%'") % i);
+            throw Error(format("bad reference ‘%1%’") % i);
         string s = string(baseName, 0, pos);
         assert(s.size() == refLength);
         assert(backMap.find(s) == backMap.end());
diff --git a/src/libstore/remote-fs-accessor.cc b/src/libstore/remote-fs-accessor.cc
index 098151f8c0f614b06d7cf1b1eba7aac3c32636b8..ca14057c2e281ab6273168302932ea76d7264501 100644
--- a/src/libstore/remote-fs-accessor.cc
+++ b/src/libstore/remote-fs-accessor.cc
@@ -17,7 +17,7 @@ std::pair<ref<FSAccessor>, Path> RemoteFSAccessor::fetch(const Path & path_)
     std::string restPath = std::string(path, storePath.size());
 
     if (!store->isValidPath(storePath))
-        throw InvalidPath(format("path '%1%' is not a valid store path") % storePath);
+        throw InvalidPath(format("path ‘%1%’ is not a valid store path") % storePath);
 
     auto i = nars.find(storePath);
     if (i != nars.end()) return {i->second, restPath};
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 5e162b03e45fe4ab4ccb6ec135fe31eb074bbc19..77faa2f801f100a88b6204ccdd40888779e6e394 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -83,11 +83,11 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
     struct sockaddr_un addr;
     addr.sun_family = AF_UNIX;
     if (socketPath.size() + 1 >= sizeof(addr.sun_path))
-        throw Error(format("socket path '%1%' is too long") % socketPath);
+        throw Error(format("socket path ‘%1%’ is too long") % socketPath);
     strcpy(addr.sun_path, socketPath.c_str());
 
     if (connect(conn->fd.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
-        throw SysError(format("cannot connect to daemon at '%1%'") % socketPath);
+        throw SysError(format("cannot connect to daemon at ‘%1%’") % socketPath);
 
     conn->from.fd = conn->fd.get();
     conn->to.fd = conn->fd.get();
@@ -277,7 +277,7 @@ void RemoteStore::queryPathInfoUncached(const Path & path,
         }
         if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 17) {
             bool valid = readInt(conn->from) != 0;
-            if (!valid) throw InvalidPath(format("path '%s' is not valid") % path);
+            if (!valid) throw InvalidPath(format("path ‘%s’ is not valid") % path);
         }
         auto info = std::make_shared<ValidPathInfo>();
         info->path = path;
diff --git a/src/libstore/s3-binary-cache-store.cc b/src/libstore/s3-binary-cache-store.cc
index 86ac2a7c485e974f7b13942ea27dcedc90681c67..1bc8576a8aef8bccec6213d2793520f7e5f8969b 100644
--- a/src/libstore/s3-binary-cache-store.cc
+++ b/src/libstore/s3-binary-cache-store.cc
@@ -81,9 +81,9 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
 
             if (!res.IsSuccess()) {
                 if (res.GetError().GetErrorType() != Aws::S3::S3Errors::NO_SUCH_BUCKET)
-                    throw Error(format("AWS error checking bucket '%s': %s") % bucketName % res.GetError().GetMessage());
+                    throw Error(format("AWS error checking bucket ‘%s’: %s") % bucketName % res.GetError().GetMessage());
 
-                checkAws(format("AWS error creating bucket '%s'") % bucketName,
+                checkAws(format("AWS error creating bucket ‘%s’") % bucketName,
                     client->CreateBucket(
                         Aws::S3::Model::CreateBucketRequest()
                         .WithBucket(bucketName)
@@ -132,7 +132,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
             if (error.GetErrorType() == Aws::S3::S3Errors::UNKNOWN // FIXME
                 && error.GetMessage().find("404") != std::string::npos)
                 return false;
-            throw Error(format("AWS error fetching '%s': %s") % path % error.GetMessage());
+            throw Error(format("AWS error fetching ‘%s’: %s") % path % error.GetMessage());
         }
 
         return true;
@@ -154,14 +154,14 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
 
         auto now1 = std::chrono::steady_clock::now();
 
-        auto result = checkAws(format("AWS error uploading '%s'") % path,
+        auto result = checkAws(format("AWS error uploading ‘%s’") % path,
             client->PutObject(request));
 
         auto now2 = std::chrono::steady_clock::now();
 
         auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count();
 
-        printInfo(format("uploaded 's3://%1%/%2%' (%3% bytes) in %4% ms")
+        printInfo(format("uploaded ‘s3://%1%/%2%’ (%3% bytes) in %4% ms")
             % bucketName % path % data.size() % duration);
 
         stats.putTimeMs += duration;
@@ -172,7 +172,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
         std::function<void(std::exception_ptr exc)> failure) override
     {
         sync2async<std::shared_ptr<std::string>>(success, failure, [&]() {
-            debug(format("fetching 's3://%1%/%2%'...") % bucketName % path);
+            debug(format("fetching ‘s3://%1%/%2%’...") % bucketName % path);
 
             auto request =
                 Aws::S3::Model::GetObjectRequest()
@@ -189,7 +189,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
 
                 auto now1 = std::chrono::steady_clock::now();
 
-                auto result = checkAws(format("AWS error fetching '%s'") % path,
+                auto result = checkAws(format("AWS error fetching ‘%s’") % path,
                     client->GetObject(request));
 
                 auto now2 = std::chrono::steady_clock::now();
@@ -198,7 +198,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
 
                 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count();
 
-                printMsg(lvlTalkative, format("downloaded 's3://%1%/%2%' (%3% bytes) in %4% ms")
+                printMsg(lvlTalkative, format("downloaded ‘s3://%1%/%2%’ (%3% bytes) in %4% ms")
                     % bucketName % path % res.size() % duration);
 
                 stats.getBytes += res.size();
@@ -219,9 +219,9 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
         std::string marker;
 
         do {
-            debug(format("listing bucket 's3://%s' from key '%s'...") % bucketName % marker);
+            debug(format("listing bucket ‘s3://%s’ from key ‘%s’...") % bucketName % marker);
 
-            auto res = checkAws(format("AWS error listing bucket '%s'") % bucketName,
+            auto res = checkAws(format("AWS error listing bucket ‘%s’") % bucketName,
                 client->ListObjects(
                     Aws::S3::Model::ListObjectsRequest()
                     .WithBucket(bucketName)
@@ -230,7 +230,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
 
             auto & contents = res.GetContents();
 
-            debug(format("got %d keys, next marker '%s'")
+            debug(format("got %d keys, next marker ‘%s’")
                 % contents.size() % res.GetNextMarker());
 
             for (auto object : contents) {
diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc
index d3d48233bcc39846b5106fc051d80632f247c4fa..0197b091cd12be969522a11407448cb807a4e8b6 100644
--- a/src/libstore/sqlite.cc
+++ b/src/libstore/sqlite.cc
@@ -39,7 +39,7 @@ SQLite::SQLite(const Path & path)
 {
     if (sqlite3_open_v2(path.c_str(), &db,
             SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0) != SQLITE_OK)
-        throw Error(format("cannot open SQLite database '%s'") % path);
+        throw Error(format("cannot open SQLite database ‘%s’") % path);
 }
 
 SQLite::~SQLite()
@@ -55,7 +55,7 @@ SQLite::~SQLite()
 void SQLite::exec(const std::string & stmt)
 {
     if (sqlite3_exec(db, stmt.c_str(), 0, 0, 0) != SQLITE_OK)
-        throwSQLiteError(db, format("executing SQLite statement '%s'") % stmt);
+        throwSQLiteError(db, format("executing SQLite statement ‘%s’") % stmt);
 }
 
 void SQLiteStmt::create(sqlite3 * db, const string & s)
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index b14277f9f7a6f5d48b8a52531750a23d52920399..37a2d45fefe0745c0f7e427ffc892236af3d6486 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -27,14 +27,14 @@ bool Store::isStorePath(const Path & path) const
 void Store::assertStorePath(const Path & path) const
 {
     if (!isStorePath(path))
-        throw Error(format("path '%1%' is not in the Nix store") % path);
+        throw Error(format("path ‘%1%’ is not in the Nix store") % path);
 }
 
 
 Path Store::toStorePath(const Path & path) const
 {
     if (!isInStore(path))
-        throw Error(format("path '%1%' is not in the Nix store") % path);
+        throw Error(format("path ‘%1%’ is not in the Nix store") % path);
     Path::size_type slash = path.find('/', storeDir.size() + 1);
     if (slash == Path::npos)
         return path;
@@ -52,7 +52,7 @@ Path Store::followLinksToStore(const Path & _path) const
         path = absPath(target, dirOf(path));
     }
     if (!isInStore(path))
-        throw Error(format("path '%1%' is not in the Nix store") % path);
+        throw Error(format("path ‘%1%’ is not in the Nix store") % path);
     return path;
 }
 
@@ -85,14 +85,14 @@ void checkStoreName(const string & name)
     /* Disallow names starting with a dot for possible security
        reasons (e.g., "." and ".."). */
     if (string(name, 0, 1) == ".")
-        throw Error(format("illegal name: '%1%'") % name);
+        throw Error(format("illegal name: ‘%1%’") % name);
     for (auto & i : name)
         if (!((i >= 'A' && i <= 'Z') ||
               (i >= 'a' && i <= 'z') ||
               (i >= '0' && i <= '9') ||
               validChars.find(i) != string::npos))
         {
-            throw Error(format("invalid character '%1%' in name '%2%'")
+            throw Error(format("invalid character ‘%1%’ in name ‘%2%’")
                 % i % name);
         }
 }
@@ -312,7 +312,7 @@ void Store::queryPathInfo(const Path & storePath,
             if (res) {
                 stats.narInfoReadAverted++;
                 if (!*res)
-                    throw InvalidPath(format("path '%s' is not valid") % storePath);
+                    throw InvalidPath(format("path ‘%s’ is not valid") % storePath);
                 return success(ref<ValidPathInfo>(*res));
             }
         }
@@ -327,7 +327,7 @@ void Store::queryPathInfo(const Path & storePath,
                         res.first == NarInfoDiskCache::oInvalid ? 0 : res.second);
                     if (res.first == NarInfoDiskCache::oInvalid ||
                         (res.second->path != storePath && storePathToName(storePath) != ""))
-                        throw InvalidPath(format("path '%s' is not valid") % storePath);
+                        throw InvalidPath(format("path ‘%s’ is not valid") % storePath);
                 }
                 return success(ref<ValidPathInfo>(res.second));
             }
@@ -352,7 +352,7 @@ void Store::queryPathInfo(const Path & storePath,
                 || (info->path != storePath && storePathToName(storePath) != ""))
             {
                 stats.narInfoMissing++;
-                return failure(std::make_exception_ptr(InvalidPath(format("path '%s' is not valid") % storePath)));
+                return failure(std::make_exception_ptr(InvalidPath(format("path ‘%s’ is not valid") % storePath)));
             }
 
             callSuccess(success, failure, ref<ValidPathInfo>(info));
@@ -514,7 +514,7 @@ string showPaths(const PathSet & paths)
     string s;
     for (auto & i : paths) {
         if (s.size() != 0) s += ", ";
-        s += "'" + i + "'";
+        s += "‘" + i + "’";
     }
     return s;
 }
@@ -523,7 +523,7 @@ string showPaths(const PathSet & paths)
 std::string ValidPathInfo::fingerprint() const
 {
     if (narSize == 0 || !narHash)
-        throw Error(format("cannot calculate fingerprint of path '%s' because its size/hash is not known")
+        throw Error(format("cannot calculate fingerprint of path ‘%s’ because its size/hash is not known")
             % path);
     return
         "1;" + path + ";"
@@ -542,7 +542,7 @@ void ValidPathInfo::sign(const SecretKey & secretKey)
 bool ValidPathInfo::isContentAddressed(const Store & store) const
 {
     auto warn = [&]() {
-        printError(format("warning: path '%s' claims to be content-addressed but isn't") % path);
+        printError(format("warning: path ‘%s’ claims to be content-addressed but isn't") % path);
     };
 
     if (hasPrefix(ca, "text:")) {
@@ -625,7 +625,7 @@ ref<Store> openStore(const std::string & uri_)
         if (store) return ref<Store>(store);
     }
 
-    throw Error(format("don't know how to open Nix store '%s'") % uri);
+    throw Error(format("don't know how to open Nix store ‘%s’") % uri);
 }
 
 
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 36c2df79ad87f28de7682c9e38d2851d52f3bd8c..2ea74d90e78eba6e182a2f00139178eafdcb09d6 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -131,16 +131,16 @@ struct ValidPathInfo
 
        Ideally, the content-addressability assertion would just be a
        Boolean, and the store path would be computed from
-       'storePathToName(path)', 'narHash' and 'references'. However,
+       ‘storePathToName(path)’, ‘narHash’ and ‘references’. However,
        1) we've accumulated several types of content-addressed paths
        over the years; and 2) fixed-output derivations support
        multiple hash algorithms and serialisation methods (flat file
-       vs NAR). Thus, 'ca' has one of the following forms:
+       vs NAR). Thus, ‘ca’ has one of the following forms:
 
-       * 'text:sha256:<sha256 hash of file contents>': For paths
+       * ‘text:sha256:<sha256 hash of file contents>’: For paths
          computed by makeTextPath() / addTextToStore().
 
-       * 'fixed:<r?>:<ht>:<h>': For paths computed by
+       * ‘fixed:<r?>:<ht>:<h>’: For paths computed by
          makeFixedOutputPath() / addToStore().
     */
     std::string ca;
@@ -242,15 +242,15 @@ public:
 
     virtual std::string getUri() = 0;
 
-    /* Return true if 'path' is in the Nix store (but not the Nix
+    /* Return true if ‘path’ is in the Nix store (but not the Nix
        store itself). */
     bool isInStore(const Path & path) const;
 
-    /* Return true if 'path' is a store path, i.e. a direct child of
+    /* Return true if ‘path’ is a store path, i.e. a direct child of
        the Nix store. */
     bool isStorePath(const Path & path) const;
 
-    /* Throw an exception if 'path' is not a store path. */
+    /* Throw an exception if ‘path’ is not a store path. */
     void assertStorePath(const Path & path) const;
 
     /* Chop off the parts after the top-level store name, e.g.,
@@ -363,7 +363,7 @@ public:
 
     /* Query substitute info (i.e. references, derivers and download
        sizes) of a set of paths.  If a path does not have substitute
-       info, it's omitted from the resulting 'infos' map. */
+       info, it's omitted from the resulting ‘infos’ map. */
     virtual void querySubstitutablePathInfos(const PathSet & paths,
         SubstitutablePathInfos & infos) = 0;
 
@@ -401,7 +401,7 @@ public:
     virtual void buildPaths(const PathSet & paths, BuildMode buildMode = bmNormal) = 0;
 
     /* Build a single non-materialized derivation (i.e. not from an
-       on-disk .drv file). Note that 'drvPath' is only used for
+       on-disk .drv file). Note that ‘drvPath’ is only used for
        informational purposes. */
     virtual BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
         BuildMode buildMode = bmNormal) = 0;
@@ -503,8 +503,8 @@ public:
        relation.  If p refers to q, then p preceeds q in this list. */
     Paths topoSortPaths(const PathSet & paths);
 
-    /* Export multiple paths in the format expected by 'nix-store
-       --import'. */
+    /* Export multiple paths in the format expected by ‘nix-store
+       --import’. */
     void exportPaths(const Paths & paths, Sink & sink);
 
     void exportPath(const Path & path, Sink & sink);
@@ -573,7 +573,7 @@ string storePathToName(const Path & path);
 /* Extract the hash part of the given store path. */
 string storePathToHash(const Path & path);
 
-/* Check whether 'name' is a valid store path name part, i.e. contains
+/* Check whether ‘name’ is a valid store path name part, i.e. contains
    only the characters [a-zA-Z0-9\+\-\.\_\?\=] and doesn't start with
    a dot. */
 void checkStoreName(const string & name);
@@ -596,17 +596,17 @@ void removeTempRoots();
 
 
 /* Return a Store object to access the Nix store denoted by
-   'uri' (slight misnomer...). Supported values are:
+   ‘uri’ (slight misnomer...). Supported values are:
 
-   * 'direct': The Nix store in /nix/store and database in
+   * ‘direct’: The Nix store in /nix/store and database in
      /nix/var/nix/db, accessed directly.
 
-   * 'daemon': The Nix store accessed via a Unix domain socket
+   * ‘daemon’: The Nix store accessed via a Unix domain socket
      connection to nix-daemon.
 
-   * 'file://<path>': A binary cache stored in <path>.
+   * ‘file://<path>’: A binary cache stored in <path>.
 
-   If 'uri' is empty, it defaults to 'direct' or 'daemon' depending on
+   If ‘uri’ is empty, it defaults to ‘direct’ or ‘daemon’ depending on
    whether the user has write access to the local Nix store/database.
    set to true *unless* you're going to collect garbage. */
 ref<Store> openStore(const std::string & uri = getEnv("NIX_REMOTE"));
@@ -622,8 +622,8 @@ enum StoreType {
 StoreType getStoreType(const std::string & uri = getEnv("NIX_REMOTE"), const std::string & stateDir = settings.nixStateDir);
 
 /* Return the default substituter stores, defined by the
-   'substituters' option and various legacy options like
-   'binary-caches'. */
+   ‘substituters’ option and various legacy options like
+   ‘binary-caches’. */
 std::list<ref<Store>> getDefaultSubstituters();
 
 
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index 93e1ce20f933cbe6a9ecaa9f7582e8a9d8afd3c0..fbba7f853f954a72ba2f95cd670cd42e52a012e0 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -40,7 +40,7 @@ static void dumpContents(const Path & path, size_t size,
     sink << "contents" << size;
 
     AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
-    if (!fd) throw SysError(format("opening file '%1%'") % path);
+    if (!fd) throw SysError(format("opening file ‘%1%’") % path);
 
     unsigned char buf[65536];
     size_t left = size;
@@ -60,7 +60,7 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
 {
     struct stat st;
     if (lstat(path.c_str(), &st))
-        throw SysError(format("getting attributes of path '%1%'") % path);
+        throw SysError(format("getting attributes of path ‘%1%’") % path);
 
     sink << "(";
 
@@ -82,11 +82,11 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
                 string name(i.name);
                 size_t pos = i.name.find(caseHackSuffix);
                 if (pos != string::npos) {
-                    debug(format("removing case hack suffix from '%1%'") % (path + "/" + i.name));
+                    debug(format("removing case hack suffix from ‘%1%’") % (path + "/" + i.name));
                     name.erase(pos);
                 }
                 if (unhacked.find(name) != unhacked.end())
-                    throw Error(format("file name collision in between '%1%' and '%2%'")
+                    throw Error(format("file name collision in between ‘%1%’ and ‘%2%’")
                         % (path + "/" + unhacked[name]) % (path + "/" + i.name));
                 unhacked[name] = i.name;
             } else
@@ -103,7 +103,7 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
     else if (S_ISLNK(st.st_mode))
         sink << "type" << "symlink" << "target" << readLink(path);
 
-    else throw Error(format("file '%1%' has an unsupported type") % path);
+    else throw Error(format("file ‘%1%’ has an unsupported type") % path);
 
     sink << ")";
 }
@@ -239,14 +239,14 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
                 } else if (s == "name") {
                     name = readString(source);
                     if (name.empty() || name == "." || name == ".." || name.find('/') != string::npos || name.find((char) 0) != string::npos)
-                        throw Error(format("NAR contains invalid file name '%1%'") % name);
+                        throw Error(format("NAR contains invalid file name ‘%1%’") % name);
                     if (name <= prevName)
                         throw Error("NAR directory is not sorted");
                     prevName = name;
                     if (useCaseHack) {
                         auto i = names.find(name);
                         if (i != names.end()) {
-                            debug(format("case collision between '%1%' and '%2%'") % i->first % name);
+                            debug(format("case collision between ‘%1%’ and ‘%2%’") % i->first % name);
                             name += caseHackSuffix;
                             name += std::to_string(++i->second);
                         } else
@@ -295,14 +295,14 @@ struct RestoreSink : ParseSink
     {
         Path p = dstPath + path;
         if (mkdir(p.c_str(), 0777) == -1)
-            throw SysError(format("creating directory '%1%'") % p);
+            throw SysError(format("creating directory ‘%1%’") % p);
     };
 
     void createRegularFile(const Path & path)
     {
         Path p = dstPath + path;
         fd = open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666);
-        if (!fd) throw SysError(format("creating file '%1%'") % p);
+        if (!fd) throw SysError(format("creating file ‘%1%’") % p);
     }
 
     void isExecutable()
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index e381a299f0275546a513e7198f8692e345baa1e3..115484f9e6c7d0fc45239cad61dad03ddbb554bf 100644
--- a/src/libutil/args.cc
+++ b/src/libutil/args.cc
@@ -35,7 +35,7 @@ void Args::parseCmdline(const Strings & _cmdline)
         }
         else if (!dashDash && std::string(arg, 0, 1) == "-") {
             if (!processFlag(pos, cmdline.end()))
-                throw UsageError(format("unrecognised flag '%1%'") % arg);
+                throw UsageError(format("unrecognised flag ‘%1%’") % arg);
         }
         else {
             pendingArgs.push_back(*pos++);
@@ -88,7 +88,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
         Strings args;
         for (size_t n = 0 ; n < flag.arity; ++n) {
             if (pos == end)
-                throw UsageError(format("flag '%1%' requires %2% argument(s)")
+                throw UsageError(format("flag ‘%1%’ requires %2% argument(s)")
                     % name % flag.arity);
             args.push_back(*pos++);
         }
@@ -116,7 +116,7 @@ bool Args::processArgs(const Strings & args, bool finish)
 {
     if (expectedArgs.empty()) {
         if (!args.empty())
-            throw UsageError(format("unexpected argument '%1%'") % args.front());
+            throw UsageError(format("unexpected argument ‘%1%’") % args.front());
         return true;
     }
 
@@ -140,10 +140,10 @@ bool Args::processArgs(const Strings & args, bool finish)
 
 void Args::mkHashTypeFlag(const std::string & name, HashType * ht)
 {
-    mkFlag1(0, name, "TYPE", "hash algorithm ('md5', 'sha1', 'sha256', or 'sha512')", [=](std::string s) {
+    mkFlag1(0, name, "TYPE", "hash algorithm (‘md5’, ‘sha1’, ‘sha256’, or ‘sha512’)", [=](std::string s) {
         *ht = parseHashType(s);
         if (*ht == htUnknown)
-            throw UsageError(format("unknown hash type '%1%'") % s);
+            throw UsageError(format("unknown hash type ‘%1%’") % s);
     });
 }
 
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index aa0f45a653a888d627e4c3b05eaa780b4b5ef889..ac12f8be633a9e4372da31f6d5e751e745cb7b37 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -126,7 +126,7 @@ public:
         mkFlag(shortName, longName, {"N"}, description, 1, [=](Strings ss) {
             I n;
             if (!string2Int(ss.front(), n))
-                throw UsageError(format("flag '--%1%' requires a integer argument") % longName);
+                throw UsageError(format("flag ‘--%1%’ requires a integer argument") % longName);
             fun(n);
         });
     }
diff --git a/src/libutil/compression.cc b/src/libutil/compression.cc
index 0532c9699d38cf0b50a04b944277cbcd59671363..a3bbb5170d9f29aaf8f43c9e876d9b4a83bc5df8 100644
--- a/src/libutil/compression.cc
+++ b/src/libutil/compression.cc
@@ -107,7 +107,7 @@ ref<std::string> decompress(const std::string & method, const std::string & in)
     else if (method == "bzip2")
         return decompressBzip2(in);
     else
-        throw UnknownCompressionMethod(format("unknown compression method '%s'") % method);
+        throw UnknownCompressionMethod(format("unknown compression method ‘%s’") % method);
 }
 
 struct NoneSink : CompressionSink
@@ -270,7 +270,7 @@ ref<CompressionSink> makeCompressionSink(const std::string & method, Sink & next
     else if (method == "bzip2")
         return make_ref<BzipSink>(nextSink);
     else
-        throw UnknownCompressionMethod(format("unknown compression method '%s'") % method);
+        throw UnknownCompressionMethod(format("unknown compression method ‘%s’") % method);
 }
 
 }
diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc
index 27bd010956b1ad78d21bbc679223076a52e9faef..49e781980f3ad2f3bfe12319f9df75ae7ccc36a4 100644
--- a/src/libutil/hash.cc
+++ b/src/libutil/hash.cc
@@ -88,11 +88,11 @@ Hash parseHash(const string & s)
 {
     string::size_type colon = s.find(':');
     if (colon == string::npos)
-        throw BadHash(format("invalid hash '%s'") % s);
+        throw BadHash(format("invalid hash ‘%s’") % s);
     string hts = string(s, 0, colon);
     HashType ht = parseHashType(hts);
     if (ht == htUnknown)
-        throw BadHash(format("unknown hash type '%s'") % hts);
+        throw BadHash(format("unknown hash type ‘%s’") % hts);
     return parseHash16or32(ht, string(s, colon + 1));
 }
 
@@ -101,11 +101,11 @@ Hash parseHash(HashType ht, const string & s)
 {
     Hash hash(ht);
     if (s.length() != hash.hashSize * 2)
-        throw BadHash(format("invalid hash '%1%'") % s);
+        throw BadHash(format("invalid hash ‘%1%’") % s);
     for (unsigned int i = 0; i < hash.hashSize; i++) {
         string s2(s, i * 2, 2);
         if (!isxdigit(s2[0]) || !isxdigit(s2[1]))
-            throw BadHash(format("invalid hash '%1%'") % s);
+            throw BadHash(format("invalid hash ‘%1%’") % s);
         istringstream_nocopy str(s2);
         int n;
         str >> std::hex >> n;
@@ -160,7 +160,7 @@ Hash parseHash32(HashType ht, const string & s)
         for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
             if (base32Chars[digit] == c) break;
         if (digit >= 32)
-            throw BadHash(format("invalid base-32 hash '%1%'") % s);
+            throw BadHash(format("invalid base-32 hash ‘%1%’") % s);
         unsigned int b = n * 5;
         unsigned int i = b / 8;
         unsigned int j = b % 8;
@@ -182,7 +182,7 @@ Hash parseHash16or32(HashType ht, const string & s)
         /* base-32 representation */
         hash = parseHash32(ht, s);
     else
-        throw BadHash(format("hash '%1%' has wrong length for hash type '%2%'")
+        throw BadHash(format("hash ‘%1%’ has wrong length for hash type ‘%2%’")
             % s % printHashType(ht));
     return hash;
 }
@@ -256,13 +256,13 @@ Hash hashFile(HashType ht, const Path & path)
     start(ht, ctx);
 
     AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
-    if (!fd) throw SysError(format("opening file '%1%'") % path);
+    if (!fd) throw SysError(format("opening file ‘%1%’") % path);
 
     unsigned char buf[8192];
     ssize_t n;
     while ((n = read(fd.get(), buf, sizeof(buf)))) {
         checkInterrupt();
-        if (n == -1) throw SysError(format("reading file '%1%'") % path);
+        if (n == -1) throw SysError(format("reading file ‘%1%’") % path);
         update(ht, ctx, buf, n);
     }
 
diff --git a/src/libutil/pool.hh b/src/libutil/pool.hh
index c1cea572362713b8efd47ed9d017dd05e0db16d4..f291cd578388753f04687bdf61f2fc1bea271962 100644
--- a/src/libutil/pool.hh
+++ b/src/libutil/pool.hh
@@ -24,8 +24,8 @@ namespace nix {
        conn->exec("select ...");
      }
 
-   Here, the Connection object referenced by 'conn' is automatically
-   returned to the pool when 'conn' goes out of scope.
+   Here, the Connection object referenced by ‘conn’ is automatically
+   returned to the pool when ‘conn’ goes out of scope.
 */
 
 template <class R>
diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh
index b229fc58c296b8924fabd6ff5d5789452a8938a9..f12f02543bc0565e1365230e10dbb6301f012e28 100644
--- a/src/libutil/serialise.hh
+++ b/src/libutil/serialise.hh
@@ -50,12 +50,12 @@ struct Source
 {
     virtual ~Source() { }
 
-    /* Store exactly 'len' bytes in the buffer pointed to by 'data'.
+    /* Store exactly ‘len’ bytes in the buffer pointed to by ‘data’.
        It blocks until all the requested data is available, or throws
        an error if it is not going to be available.   */
     void operator () (unsigned char * data, size_t len);
 
-    /* Store up to 'len' in the buffer pointed to by 'data', and
+    /* Store up to ‘len’ in the buffer pointed to by ‘data’, and
        return the number of bytes stored.  If blocks until at least
        one byte is available. */
     virtual size_t read(unsigned char * data, size_t len) = 0;
diff --git a/src/libutil/types.hh b/src/libutil/types.hh
index 6834257012d691c310d0c21370f909fe1c75cd83..b9a93d27d2add81fe46046b8875cf7f2b146c2e9 100644
--- a/src/libutil/types.hh
+++ b/src/libutil/types.hh
@@ -41,9 +41,9 @@ struct FormatOrString
 };
 
 
-/* A helper for formatting strings. 'fmt(format, a_0, ..., a_n)' is
-   equivalent to 'boost::format(format) % a_0 % ... %
-   ... a_n'. However, 'fmt(s)' is equivalent to 's' (so no %-expansion
+/* A helper for formatting strings. ‘fmt(format, a_0, ..., a_n)’ is
+   equivalent to ‘boost::format(format) % a_0 % ... %
+   ... a_n’. However, ‘fmt(s)’ is equivalent to ‘s’ (so no %-expansion
    takes place). */
 
 inline void formatHelper(boost::format & f)
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index c4dfdd96ea2b108782845a613513c2d876a5e2d0..ce16cc30a5c7714e51cc42ae819111e56b2520ec 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -97,7 +97,7 @@ Path canonPath(const Path & path, bool resolveSymlinks)
     string s;
 
     if (path[0] != '/')
-        throw Error(format("not an absolute path: '%1%'") % path);
+        throw Error(format("not an absolute path: ‘%1%’") % path);
 
     string::const_iterator i = path.begin(), end = path.end();
     string temp;
@@ -133,7 +133,7 @@ Path canonPath(const Path & path, bool resolveSymlinks)
                the symlink target might contain new symlinks). */
             if (resolveSymlinks && isLink(s)) {
                 if (++followCount >= maxFollow)
-                    throw Error(format("infinite symlink recursion in path '%1%'") % path);
+                    throw Error(format("infinite symlink recursion in path ‘%1%’") % path);
                 temp = absPath(readLink(s), dirOf(s))
                     + string(i, end);
                 i = temp.begin(); /* restart */
@@ -151,7 +151,7 @@ Path dirOf(const Path & path)
 {
     Path::size_type pos = path.rfind('/');
     if (pos == string::npos)
-        throw Error(format("invalid file name '%1%'") % path);
+        throw Error(format("invalid file name ‘%1%’") % path);
     return pos == 0 ? "/" : Path(path, 0, pos);
 }
 
@@ -188,7 +188,7 @@ struct stat lstat(const Path & path)
 {
     struct stat st;
     if (lstat(path.c_str(), &st))
-        throw SysError(format("getting status of '%1%'") % path);
+        throw SysError(format("getting status of ‘%1%’") % path);
     return st;
 }
 
@@ -210,13 +210,13 @@ Path readLink(const Path & path)
     checkInterrupt();
     struct stat st = lstat(path);
     if (!S_ISLNK(st.st_mode))
-        throw Error(format("'%1%' is not a symlink") % path);
+        throw Error(format("‘%1%’ is not a symlink") % path);
     char buf[st.st_size];
     ssize_t rlsize = readlink(path.c_str(), buf, st.st_size);
     if (rlsize == -1)
-        throw SysError(format("reading symbolic link '%1%'") % path);
+        throw SysError(format("reading symbolic link ‘%1%’") % path);
     else if (rlsize > st.st_size)
-        throw Error(format("symbolic link '%1%' size overflow %2% > %3%")
+        throw Error(format("symbolic link ‘%1%’ size overflow %2% > %3%")
             % path % rlsize % st.st_size);
     return string(buf, rlsize);
 }
@@ -235,7 +235,7 @@ DirEntries readDirectory(const Path & path)
     entries.reserve(64);
 
     AutoCloseDir dir = opendir(path.c_str());
-    if (!dir) throw SysError(format("opening directory '%1%'") % path);
+    if (!dir) throw SysError(format("opening directory ‘%1%’") % path);
 
     struct dirent * dirent;
     while (errno = 0, dirent = readdir(dir)) { /* sic */
@@ -250,7 +250,7 @@ DirEntries readDirectory(const Path & path)
 #endif
         );
     }
-    if (errno) throw SysError(format("reading directory '%1%'") % path);
+    if (errno) throw SysError(format("reading directory ‘%1%’") % path);
 
     return entries;
 }
@@ -284,7 +284,7 @@ string readFile(const Path & path, bool drain)
 {
     AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
     if (!fd)
-        throw SysError(format("opening file '%1%'") % path);
+        throw SysError(format("opening file ‘%1%’") % path);
     return drain ? drainFD(fd.get()) : readFile(fd.get());
 }
 
@@ -293,7 +293,7 @@ void writeFile(const Path & path, const string & s)
 {
     AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666);
     if (!fd)
-        throw SysError(format("opening file '%1%'") % path);
+        throw SysError(format("opening file ‘%1%’") % path);
     writeFull(fd.get(), s);
 }
 
@@ -332,7 +332,7 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed)
     struct stat st;
     if (lstat(path.c_str(), &st) == -1) {
         if (errno == ENOENT) return;
-        throw SysError(format("getting status of '%1%'") % path);
+        throw SysError(format("getting status of ‘%1%’") % path);
     }
 
     if (!S_ISDIR(st.st_mode) && st.st_nlink == 1)
@@ -343,7 +343,7 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed)
         const auto PERM_MASK = S_IRUSR | S_IWUSR | S_IXUSR;
         if ((st.st_mode & PERM_MASK) != PERM_MASK) {
             if (chmod(path.c_str(), st.st_mode | PERM_MASK) == -1)
-                throw SysError(format("chmod '%1%'") % path);
+                throw SysError(format("chmod ‘%1%’") % path);
         }
 
         for (auto & i : readDirectory(path))
@@ -352,7 +352,7 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed)
 
     if (remove(path.c_str()) == -1) {
         if (errno == ENOENT) return;
-        throw SysError(format("cannot unlink '%1%'") % path);
+        throw SysError(format("cannot unlink ‘%1%’") % path);
     }
 }
 
@@ -366,7 +366,7 @@ void deletePath(const Path & path)
 
 void deletePath(const Path & path, unsigned long long & bytesFreed)
 {
-    Activity act(*logger, lvlDebug, format("recursively deleting path '%1%'") % path);
+    Activity act(*logger, lvlDebug, format("recursively deleting path ‘%1%’") % path);
     bytesFreed = 0;
     _deletePath(path, bytesFreed);
 }
@@ -404,12 +404,12 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix,
                "wheel", then "tar" will fail to unpack archives that
                have the setgid bit set on directories. */
             if (chown(tmpDir.c_str(), (uid_t) -1, getegid()) != 0)
-                throw SysError(format("setting group of directory '%1%'") % tmpDir);
+                throw SysError(format("setting group of directory ‘%1%’") % tmpDir);
 #endif
             return tmpDir;
         }
         if (errno != EEXIST)
-            throw SysError(format("creating directory '%1%'") % tmpDir);
+            throw SysError(format("creating directory ‘%1%’") % tmpDir);
     }
 }
 
@@ -435,15 +435,15 @@ Paths createDirs(const Path & path)
     if (lstat(path.c_str(), &st) == -1) {
         created = createDirs(dirOf(path));
         if (mkdir(path.c_str(), 0777) == -1 && errno != EEXIST)
-            throw SysError(format("creating directory '%1%'") % path);
+            throw SysError(format("creating directory ‘%1%’") % path);
         st = lstat(path);
         created.push_back(path);
     }
 
     if (S_ISLNK(st.st_mode) && stat(path.c_str(), &st) == -1)
-        throw SysError(format("statting symlink '%1%'") % path);
+        throw SysError(format("statting symlink ‘%1%’") % path);
 
-    if (!S_ISDIR(st.st_mode)) throw Error(format("'%1%' is not a directory") % path);
+    if (!S_ISDIR(st.st_mode)) throw Error(format("‘%1%’ is not a directory") % path);
 
     return created;
 }
@@ -452,7 +452,7 @@ Paths createDirs(const Path & path)
 void createSymlink(const Path & target, const Path & link)
 {
     if (symlink(target.c_str(), link.c_str()))
-        throw SysError(format("creating symlink from '%1%' to '%2%'") % link % target);
+        throw SysError(format("creating symlink from ‘%1%’ to ‘%2%’") % link % target);
 }
 
 
@@ -463,7 +463,7 @@ void replaceSymlink(const Path & target, const Path & link)
     createSymlink(target, tmp);
 
     if (rename(tmp.c_str(), link.c_str()) != 0)
-        throw SysError(format("renaming '%1%' to '%2%'") % tmp % link);
+        throw SysError(format("renaming ‘%1%’ to ‘%2%’") % tmp % link);
 }
 
 
@@ -542,7 +542,7 @@ AutoDelete::~AutoDelete()
                 deletePath(path);
             else {
                 if (remove(path.c_str()) == -1)
-                    throw SysError(format("cannot unlink '%1%'") % path);
+                    throw SysError(format("cannot unlink ‘%1%’") % path);
             }
         }
     } catch (...) {
@@ -788,7 +788,7 @@ pid_t Pid::release()
 
 void killUser(uid_t uid)
 {
-    debug(format("killing all processes running under uid '%1%'") % uid);
+    debug(format("killing all processes running under uid ‘%1%’") % uid);
 
     assert(uid != 0); /* just to be safe... */
 
@@ -817,7 +817,7 @@ void killUser(uid_t uid)
 #endif
             if (errno == ESRCH) break; /* no more processes */
             if (errno != EINTR)
-                throw SysError(format("cannot kill processes for uid '%1%'") % uid);
+                throw SysError(format("cannot kill processes for uid ‘%1%’") % uid);
         }
 
         _exit(0);
@@ -825,7 +825,7 @@ void killUser(uid_t uid)
 
     int status = pid.wait(true);
     if (status != 0)
-        throw Error(format("cannot kill processes for uid '%1%': %2%") % uid % statusToString(status));
+        throw Error(format("cannot kill processes for uid ‘%1%’: %2%") % uid % statusToString(status));
 
     /* !!! We should really do some check to make sure that there are
        no processes left running under `uid', but there is no portable
@@ -919,7 +919,7 @@ string runProgram(Path program, bool searchPath, const Strings & args,
         else
             execv(program.c_str(), stringsToCharPtrs(args_).data());
 
-        throw SysError(format("executing '%1%'") % program);
+        throw SysError(format("executing ‘%1%’") % program);
     });
 
     out.writeSide = -1;
@@ -936,7 +936,7 @@ string runProgram(Path program, bool searchPath, const Strings & args,
     /* Wait for the child to finish. */
     int status = pid.wait(true);
     if (!statusOk(status))
-        throw ExecError(status, format("program '%1%' %2%")
+        throw ExecError(status, format("program ‘%1%’ %2%")
             % program % statusToString(status));
 
     return result;
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 5ffdbaa8869eea48354102b1b43cc55220714175..1ede48a65ff214ec9aea8a6ee579e6603845a1c9 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -370,7 +370,7 @@ void ignoreException();
 #define ANSI_RED "\e[31;1m"
 
 
-/* Filter out ANSI escape codes from the given string. If 'nixOnly' is
+/* Filter out ANSI escape codes from the given string. If ‘nixOnly’ is
    set, only filter escape codes generated by Nixpkgs' stdenv (used to
    denote nesting etc.). */
 string filterANSIEscapes(const string & s, bool nixOnly = false);
@@ -391,15 +391,15 @@ string get(const T & map, const string & key, const string & def = "")
 }
 
 
-/* Call 'failure' with the current exception as argument. If 'failure'
+/* Call ‘failure’ with the current exception as argument. If ‘failure’
    throws an exception, abort the program. */
 void callFailure(const std::function<void(std::exception_ptr exc)> & failure,
     std::exception_ptr exc = std::current_exception());
 
 
-/* Evaluate the function 'f'. If it returns a value, call 'success'
-   with that value as its argument. If it or 'success' throws an
-   exception, call 'failure'. If 'failure' throws an exception, abort
+/* Evaluate the function ‘f’. If it returns a value, call ‘success’
+   with that value as its argument. If it or ‘success’ throws an
+   exception, call ‘failure’. If ‘failure’ throws an exception, abort
    the program. */
 template<class T>
 void sync2async(
@@ -415,8 +415,8 @@ void sync2async(
 }
 
 
-/* Call the function 'success'. If it throws an exception, call
-   'failure'. If that throws an exception, abort the program. */
+/* Call the function ‘success’. If it throws an exception, call
+   ‘failure’. If that throws an exception, abort the program. */
 template<class T>
 void callSuccess(
     const std::function<void(T)> & success,
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index 487ccfaab14579ba2c55f92f6ac72717174f1125..08c6793577a49046f28e0ee35099f0fd5ba3851d 100755
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -322,7 +322,7 @@ int main(int argc, char ** argv)
         }
 
         if (packages && fromArgs) {
-            throw UsageError("'-p' and '-E' are mutually exclusive");
+            throw UsageError("‘-p’ and ‘-E’ are mutually exclusive");
         }
 
         if (packages) {
diff --git a/src/nix-channel/nix-channel.cc b/src/nix-channel/nix-channel.cc
index 752e0b830aa7080d2c2e67ebb9e149789ad346f9..36162782312632c22ff830c8ef5f5efa49b79648 100755
--- a/src/nix-channel/nix-channel.cc
+++ b/src/nix-channel/nix-channel.cc
@@ -35,7 +35,7 @@ static void writeChannels()
 {
     auto channelsFD = AutoCloseFD{open(channelsList.c_str(), O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, 0644)};
     if (!channelsFD)
-        throw SysError(format("opening '%1%' for writing") % channelsList);
+        throw SysError(format("opening ‘%1%’ for writing") % channelsList);
     for (const auto & channel : channels)
         writeFull(channelsFD.get(), channel.second + " " + channel.first + "\n");
 }
@@ -44,9 +44,9 @@ static void writeChannels()
 static void addChannel(const string & url, const string & name)
 {
     if (!regex_search(url, std::regex("^(file|http|https)://")))
-        throw Error(format("invalid channel URL '%1%'") % url);
+        throw Error(format("invalid channel URL ‘%1%’") % url);
     if (!regex_search(name, std::regex("^[a-zA-Z0-9_][a-zA-Z0-9_\\.-]*$")))
-        throw Error(format("invalid channel identifier '%1%'") % name);
+        throw Error(format("invalid channel identifier ‘%1%’") % name);
     readChannels();
     channels[name] = url;
     writeChannels();
@@ -224,7 +224,7 @@ int main(int argc, char ** argv)
                 throw UsageError("no command specified");
             case cAdd:
                 if (args.size() < 1 || args.size() > 2)
-                    throw UsageError("'--add' requires one or two arguments");
+                    throw UsageError("‘--add’ requires one or two arguments");
                 {
                 auto url = args[0];
                 auto name = string{};
@@ -240,12 +240,12 @@ int main(int argc, char ** argv)
                 break;
             case cRemove:
                 if (args.size() != 1)
-                    throw UsageError("'--remove' requires one argument");
+                    throw UsageError("‘--remove’ requires one argument");
                 removeChannel(args[0]);
                 break;
             case cList:
                 if (!args.empty())
-                    throw UsageError("'--list' expects no arguments");
+                    throw UsageError("‘--list’ expects no arguments");
                 readChannels();
                 for (const auto & channel : channels)
                     std::cout << channel.first << ' ' << channel.second << '\n';
@@ -255,7 +255,7 @@ int main(int argc, char ** argv)
                 break;
             case cRollback:
                 if (args.size() > 1)
-                    throw UsageError("'--rollback' has at most one argument");
+                    throw UsageError("‘--rollback’ has at most one argument");
                 auto envArgs = Strings{"--profile", profile};
                 if (args.size() == 1) {
                     envArgs.push_back("--switch-generation");
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index ce881e0d19de78c5de4c1d0696755e3dacfb37c0..90a7301873c460d057b6bb7091bd5129d7090f47 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -648,7 +648,7 @@ static void processConnection(bool trusted)
         /* Prevent users from doing something very dangerous. */
         if (geteuid() == 0 &&
             querySetting("build-users-group", "") == "")
-            throw Error("if you run 'nix-daemon' as root, then you MUST set 'build-users-group'!");
+            throw Error("if you run ‘nix-daemon’ as root, then you MUST set ‘build-users-group’!");
 #endif
 
         /* Open the store. */
@@ -829,7 +829,7 @@ static void daemonLoop(char * * argv)
         struct sockaddr_un addr;
         addr.sun_family = AF_UNIX;
         if (socketPathRel.size() >= sizeof(addr.sun_path))
-            throw Error(format("socket path '%1%' is too long") % socketPathRel);
+            throw Error(format("socket path ‘%1%’ is too long") % socketPathRel);
         strcpy(addr.sun_path, socketPathRel.c_str());
 
         unlink(socketPath.c_str());
@@ -841,13 +841,13 @@ static void daemonLoop(char * * argv)
         int res = bind(fdSocket.get(), (struct sockaddr *) &addr, sizeof(addr));
         umask(oldMode);
         if (res == -1)
-            throw SysError(format("cannot bind to socket '%1%'") % socketPath);
+            throw SysError(format("cannot bind to socket ‘%1%’") % socketPath);
 
         if (chdir("/") == -1) /* back to the root */
             throw SysError("cannot change current directory");
 
         if (listen(fdSocket.get(), 5) == -1)
-            throw SysError(format("cannot listen on socket '%1%'") % socketPath);
+            throw SysError(format("cannot listen on socket ‘%1%’") % socketPath);
     }
 
     closeOnExec(fdSocket.get());
@@ -886,7 +886,7 @@ static void daemonLoop(char * * argv)
                 trusted = true;
 
             if (!trusted && !matchUser(user, group, allowedUsers))
-                throw Error(format("user '%1%' is not allowed to connect to the Nix daemon") % user);
+                throw Error(format("user ‘%1%’ is not allowed to connect to the Nix daemon") % user);
 
             printInfo(format((string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""))
                 % (peer.pidKnown ? std::to_string(peer.pid) : "<unknown>")
@@ -961,7 +961,7 @@ int main(int argc, char * * argv)
 
                 auto socketDir = dirOf(socketPath);
                 if (chdir(socketDir.c_str()) == -1)
-                    throw SysError(format("changing to socket directory '%1%'") % socketDir);
+                    throw SysError(format("changing to socket directory ‘%1%’") % socketDir);
 
                 auto socketName = baseNameOf(socketPath);
                 auto addr = sockaddr_un{};
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index bae6d1ce722248a85734f727ee31d3bf088f3b62..908c09bc8c8a7b1daf47dc91ff169c28f8cab248 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -70,7 +70,7 @@ static string needArg(Strings::iterator & i,
     Strings & args, const string & arg)
 {
     if (i == args.end()) throw UsageError(
-        format("'%1%' requires an argument") % arg);
+        format("‘%1%’ requires an argument") % arg);
     return *i++;
 }
 
@@ -124,7 +124,7 @@ static void getAllExprs(EvalState & state,
             if (hasSuffix(attrName, ".nix"))
                 attrName = string(attrName, 0, attrName.size() - 4);
             if (attrs.find(attrName) != attrs.end()) {
-                printError(format("warning: name collision in input Nix expressions, skipping '%1%'") % path2);
+                printError(format("warning: name collision in input Nix expressions, skipping ‘%1%’") % path2);
                 continue;
             }
             attrs.insert(attrName);
@@ -133,7 +133,7 @@ static void getAllExprs(EvalState & state,
             Value & vArg(*state.allocValue());
             mkString(vArg, path2);
             if (v.attrs->size() == v.attrs->capacity())
-                throw Error(format("too many Nix expressions in directory '%1%'") % path);
+                throw Error(format("too many Nix expressions in directory ‘%1%’") % path);
             mkApp(*state.allocAttr(v, state.symbols.create(attrName)), vFun, vArg);
         }
         else if (S_ISDIR(st.st_mode))
@@ -148,7 +148,7 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
 {
     struct stat st;
     if (stat(path.c_str(), &st) == -1)
-        throw SysError(format("getting information about '%1%'") % path);
+        throw SysError(format("getting information about ‘%1%’") % path);
 
     if (isNixExpr(path, st)) {
         state.evalFile(path, v);
@@ -234,7 +234,7 @@ static void checkSelectorUse(DrvNames & selectors)
     /* Check that all selectors have been used. */
     for (auto & i : selectors)
         if (i.hits == 0 && i.fullName != "*")
-            throw Error(format("selector '%1%' matches no derivations") % i.fullName);
+            throw Error(format("selector ‘%1%’ matches no derivations") % i.fullName);
 }
 
 
@@ -305,7 +305,7 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
             for (auto & j : newest) {
                 if (multiple.find(j.second.first.name) != multiple.end())
                     printInfo(
-                        format("warning: there are multiple derivations named '%1%'; using the first one")
+                        format("warning: there are multiple derivations named ‘%1%’; using the first one")
                         % j.second.first.name);
                 matches.push_back(j.second);
             }
@@ -496,13 +496,13 @@ static void installDerivations(Globals & globals,
                 if (!globals.preserveInstalled &&
                     newNames.find(drvName.name) != newNames.end() &&
                     !keep(i))
-                    printInfo(format("replacing old '%1%'") % i.name);
+                    printInfo(format("replacing old ‘%1%’") % i.name);
                 else
                     allElems.push_back(i);
             }
 
             for (auto & i : newElems)
-                printInfo(format("installing '%1%'") % i.name);
+                printInfo(format("installing ‘%1%’") % i.name);
         }
 
         printMissing(*globals.state, newElems);
@@ -524,7 +524,7 @@ static void opInstall(Globals & globals, Strings opFlags, Strings opArgs)
             globals.preserveInstalled = true;
         else if (arg == "--remove-all" || arg == "-r")
             globals.removeAll = true;
-        else throw UsageError(format("unknown flag '%1%'") % arg);
+        else throw UsageError(format("unknown flag ‘%1%’") % arg);
     }
 
     installDerivations(globals, opArgs, globals.profile);
@@ -605,13 +605,13 @@ static void upgradeDerivations(Globals & globals,
                     const char * action = compareVersions(drvName.version, bestVersion) <= 0
                         ? "upgrading" : "downgrading";
                     printInfo(
-                        format("%1% '%2%' to '%3%'")
+                        format("%1% ‘%2%’ to ‘%3%’")
                         % action % i.name % bestElem->name);
                     newElems.push_back(*bestElem);
                 } else newElems.push_back(i);
 
             } catch (Error & e) {
-                e.addPrefix(format("while trying to find an upgrade for '%1%':\n") % i.name);
+                e.addPrefix(format("while trying to find an upgrade for ‘%1%’:\n") % i.name);
                 throw;
             }
         }
@@ -636,7 +636,7 @@ static void opUpgrade(Globals & globals, Strings opFlags, Strings opArgs)
         else if (arg == "--leq") upgradeType = utLeq;
         else if (arg == "--eq") upgradeType = utEq;
         else if (arg == "--always") upgradeType = utAlways;
-        else throw UsageError(format("unknown flag '%1%'") % arg);
+        else throw UsageError(format("unknown flag ‘%1%’") % arg);
     }
 
     upgradeDerivations(globals, opArgs, upgradeType);
@@ -655,9 +655,9 @@ static void setMetaFlag(EvalState & state, DrvInfo & drv,
 static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
 {
     if (opFlags.size() > 0)
-        throw UsageError(format("unknown flag '%1%'") % opFlags.front());
+        throw UsageError(format("unknown flag ‘%1%’") % opFlags.front());
     if (opArgs.size() < 2)
-        throw UsageError("not enough arguments to '--set-flag'");
+        throw UsageError("not enough arguments to ‘--set-flag’");
 
     Strings::iterator arg = opArgs.begin();
     string flagName = *arg++;
@@ -674,7 +674,7 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
             DrvName drvName(i.name);
             for (auto & j : selectors)
                 if (j.matches(drvName)) {
-                    printInfo(format("setting flag on '%1%'") % i.name);
+                    printInfo(format("setting flag on ‘%1%’") % i.name);
                     j.hits++;
                     setMetaFlag(*globals.state, i, flagName, flagValue);
                     break;
@@ -698,7 +698,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
     for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) {
         string arg = *i++;
         if (parseInstallSourceOptions(globals, i, opFlags, arg)) ;
-        else throw UsageError(format("unknown flag '%1%'") % arg);
+        else throw UsageError(format("unknown flag ‘%1%’") % arg);
     }
 
     DrvInfos elems;
@@ -748,7 +748,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
                 if ((isPath(j) && i.queryOutPath() == globals.state->store->followLinksToStorePath(j))
                     || DrvName(j).matches(drvName))
                 {
-                    printInfo(format("uninstalling '%1%'") % i.name);
+                    printInfo(format("uninstalling ‘%1%’") % i.name);
                     found = true;
                     break;
                 }
@@ -766,7 +766,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
 static void opUninstall(Globals & globals, Strings opFlags, Strings opArgs)
 {
     if (opFlags.size() > 0)
-        throw UsageError(format("unknown flag '%1%'") % opFlags.front());
+        throw UsageError(format("unknown flag ‘%1%’") % opFlags.front());
     uninstallDerivations(globals, opArgs, globals.profile);
 }
 
@@ -874,7 +874,7 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems)
             auto placeholder = metaObj.placeholder(j);
             Value * v = i.queryMeta(j);
             if (!v) {
-                printError(format("derivation '%1%' has invalid meta attribute '%2%'") % i.name % j);
+                printError(format("derivation ‘%1%’ has invalid meta attribute ‘%2%’") % i.name % j);
                 placeholder.write(nullptr);
             } else {
                 PathSet context;
@@ -924,7 +924,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
         else if (arg == "--attr" || arg == "-A")
             attrPath = needArg(i, opFlags, arg);
         else
-            throw UsageError(format("unknown flag '%1%'") % arg);
+            throw UsageError(format("unknown flag ‘%1%’") % arg);
     }
 
 
@@ -971,7 +971,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
             try {
                 paths.insert(i.queryOutPath());
             } catch (AssertionError & e) {
-                printMsg(lvlTalkative, format("skipping derivation named '%1%' which gives an assertion failure") % i.name);
+                printMsg(lvlTalkative, format("skipping derivation named ‘%1%’ which gives an assertion failure") % i.name);
                 i.setFailed();
             }
         validPaths = globals.state->store->queryValidPaths(paths);
@@ -997,7 +997,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
         try {
             if (i.hasFailed()) continue;
 
-            Activity act(*logger, lvlDebug, format("outputting query result '%1%'") % i.attrPath);
+            Activity act(*logger, lvlDebug, format("outputting query result ‘%1%’") % i.attrPath);
 
             if (globals.prebuiltOnly &&
                 validPaths.find(i.queryOutPath()) == validPaths.end() &&
@@ -1118,7 +1118,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
                             attrs2["name"] = j;
                             Value * v = i.queryMeta(j);
                             if (!v)
-                                printError(format("derivation '%1%' has invalid meta attribute '%2%'") % i.name % j);
+                                printError(format("derivation ‘%1%’ has invalid meta attribute ‘%2%’") % i.name % j);
                             else {
                                 if (v->type == tString) {
                                     attrs2["type"] = "string";
@@ -1169,9 +1169,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
             cout.flush();
 
         } catch (AssertionError & e) {
-            printMsg(lvlTalkative, format("skipping derivation named '%1%' which gives an assertion failure") % i.name);
+            printMsg(lvlTalkative, format("skipping derivation named ‘%1%’ which gives an assertion failure") % i.name);
         } catch (Error & e) {
-            e.addPrefix(format("while querying the derivation named '%1%':\n") % i.name);
+            e.addPrefix(format("while querying the derivation named ‘%1%’:\n") % i.name);
             throw;
         }
     }
@@ -1183,7 +1183,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
 static void opSwitchProfile(Globals & globals, Strings opFlags, Strings opArgs)
 {
     if (opFlags.size() > 0)
-        throw UsageError(format("unknown flag '%1%'") % opFlags.front());
+        throw UsageError(format("unknown flag ‘%1%’") % opFlags.front());
     if (opArgs.size() != 1)
         throw UsageError(format("exactly one argument expected"));
 
@@ -1231,7 +1231,7 @@ static void switchGeneration(Globals & globals, int dstGen)
 static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArgs)
 {
     if (opFlags.size() > 0)
-        throw UsageError(format("unknown flag '%1%'") % opFlags.front());
+        throw UsageError(format("unknown flag ‘%1%’") % opFlags.front());
     if (opArgs.size() != 1)
         throw UsageError(format("exactly one argument expected"));
 
@@ -1246,7 +1246,7 @@ static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArg
 static void opRollback(Globals & globals, Strings opFlags, Strings opArgs)
 {
     if (opFlags.size() > 0)
-        throw UsageError(format("unknown flag '%1%'") % opFlags.front());
+        throw UsageError(format("unknown flag ‘%1%’") % opFlags.front());
     if (opArgs.size() != 0)
         throw UsageError(format("no arguments expected"));
 
@@ -1257,7 +1257,7 @@ static void opRollback(Globals & globals, Strings opFlags, Strings opArgs)
 static void opListGenerations(Globals & globals, Strings opFlags, Strings opArgs)
 {
     if (opFlags.size() > 0)
-        throw UsageError(format("unknown flag '%1%'") % opFlags.front());
+        throw UsageError(format("unknown flag ‘%1%’") % opFlags.front());
     if (opArgs.size() != 0)
         throw UsageError(format("no arguments expected"));
 
@@ -1284,7 +1284,7 @@ static void opListGenerations(Globals & globals, Strings opFlags, Strings opArgs
 static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opArgs)
 {
     if (opFlags.size() > 0)
-        throw UsageError(format("unknown flag '%1%'") % opFlags.front());
+        throw UsageError(format("unknown flag ‘%1%’") % opFlags.front());
 
     if (opArgs.size() == 1 && opArgs.front() == "old") {
         deleteOldGenerations(globals.profile, globals.dryRun);
@@ -1295,7 +1295,7 @@ static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opAr
         for (auto & i : opArgs) {
             unsigned int n;
             if (!string2Int(i, n))
-                throw UsageError(format("invalid generation number '%1%'") % i);
+                throw UsageError(format("invalid generation number ‘%1%’") % i);
             gens.insert(n);
         }
         deleteGenerations(globals.profile, gens, globals.dryRun);
diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc
index b37d8ba9bbb2be9b55107b994fec5522d81945fa..e9997fae57ba79b7b49fee575f8279caa9287c06 100644
--- a/src/nix-env/user-env.cc
+++ b/src/nix-env/user-env.cc
@@ -139,7 +139,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
 
         Path lockTokenCur = optimisticLockProfile(profile);
         if (lockToken != lockTokenCur) {
-            printError(format("profile '%1%' changed while we were busy; restarting") % profile);
+            printError(format("profile ‘%1%’ changed while we were busy; restarting") % profile);
             return false;
         }
 
diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc
index 0c1023f9f3d4975c5646bd3b3b28b717739984bd..c1b0b0ea092d9e0212d4735b40b40a6b8b3205bc 100644
--- a/src/nix-instantiate/nix-instantiate.cc
+++ b/src/nix-instantiate/nix-instantiate.cc
@@ -72,7 +72,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
                 /* What output do we want? */
                 string outputName = i.queryOutputName();
                 if (outputName == "")
-                    throw Error(format("derivation '%1%' lacks an 'outputName' attribute ") % drvPath);
+                    throw Error(format("derivation ‘%1%’ lacks an ‘outputName’ attribute ") % drvPath);
 
                 if (gcRoot == "")
                     printGCWarning();
@@ -171,7 +171,7 @@ int main(int argc, char * * argv)
         if (findFile) {
             for (auto & i : files) {
                 Path p = state.findFile(i);
-                if (p == "") throw Error(format("unable to find '%1%'") % i);
+                if (p == "") throw Error(format("unable to find ‘%1%’") % i);
                 std::cout << p << std::endl;
             }
             return;
diff --git a/src/nix-prefetch-url/nix-prefetch-url.cc b/src/nix-prefetch-url/nix-prefetch-url.cc
index 99c3bebf0a1dd9922f4e33bac7fce237d5fa06f6..acf60302569005a0089b0d09966ee1cd543805c8 100644
--- a/src/nix-prefetch-url/nix-prefetch-url.cc
+++ b/src/nix-prefetch-url/nix-prefetch-url.cc
@@ -12,7 +12,7 @@
 using namespace nix;
 
 
-/* If 'uri' starts with 'mirror://', then resolve it using the list of
+/* If ‘uri’ starts with ‘mirror://’, then resolve it using the list of
    mirrors defined in Nixpkgs. */
 string resolveMirrorUri(EvalState & state, string uri)
 {
@@ -29,11 +29,11 @@ string resolveMirrorUri(EvalState & state, string uri)
 
     auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName));
     if (mirrorList == vMirrors.attrs->end())
-        throw Error(format("unknown mirror name '%1%'") % mirrorName);
+        throw Error(format("unknown mirror name ‘%1%’") % mirrorName);
     state.forceList(*mirrorList->value);
 
     if (mirrorList->value->listSize() < 1)
-        throw Error(format("mirror URI '%1%' did not expand to anything") % uri);
+        throw Error(format("mirror URI ‘%1%’ did not expand to anything") % uri);
 
     string mirror = state.forceString(*mirrorList->value->listElems()[0]);
     return mirror + (hasSuffix(mirror, "/") ? "" : "/") + string(s, p + 1);
@@ -65,7 +65,7 @@ int main(int argc, char * * argv)
                 string s = getArg(*arg, arg, end);
                 ht = parseHashType(s);
                 if (ht == htUnknown)
-                    throw UsageError(format("unknown hash type '%1%'") % s);
+                    throw UsageError(format("unknown hash type ‘%1%’") % s);
             }
             else if (*arg == "--print-path")
                 printPath = true;
@@ -113,10 +113,10 @@ int main(int argc, char * * argv)
             /* Extract the URI. */
             auto attr = v.attrs->find(state.symbols.create("urls"));
             if (attr == v.attrs->end())
-                throw Error("attribute set does not contain a 'urls' attribute");
+                throw Error("attribute set does not contain a ‘urls’ attribute");
             state.forceList(*attr->value);
             if (attr->value->listSize() < 1)
-                throw Error("'urls' list is empty");
+                throw Error("‘urls’ list is empty");
             uri = state.forceString(*attr->value->listElems()[0]);
 
             /* Extract the hash mode. */
@@ -138,7 +138,7 @@ int main(int argc, char * * argv)
         if (name.empty())
             name = baseNameOf(uri);
         if (name.empty())
-            throw Error(format("cannot figure out file name for '%1%'") % uri);
+            throw Error(format("cannot figure out file name for ‘%1%’") % uri);
 
         /* If an expected hash is given, the file may already exist in
            the store. */
@@ -189,7 +189,7 @@ int main(int argc, char * * argv)
             hash = unpack ? hashPath(ht, tmpFile).first : hashString(ht, *result.data);
 
             if (expectedHash != Hash(ht) && expectedHash != hash)
-                throw Error(format("hash mismatch for '%1%'") % uri);
+                throw Error(format("hash mismatch for ‘%1%’") % uri);
 
             /* Copy the file to the Nix store. FIXME: if RemoteStore
                implemented addToStoreFromDump() and downloadFile()
@@ -201,7 +201,7 @@ int main(int argc, char * * argv)
         }
 
         if (!printPath)
-            printInfo(format("path is '%1%'") % storePath);
+            printInfo(format("path is ‘%1%’") % storePath);
 
         std::cout << printHash16or32(hash) << std::endl;
         if (printPath)
diff --git a/src/nix-store/dotgraph.cc b/src/nix-store/dotgraph.cc
index 51dedcf0a09247382b90a8cb5ec3eb39eadfe061..356a82510124082c3f91a8822148d4d4314260b6 100644
--- a/src/nix-store/dotgraph.cc
+++ b/src/nix-store/dotgraph.cc
@@ -77,7 +77,7 @@ void printClosure(const Path & nePath, const StoreExpr & fs)
 
             ClosureElems::const_iterator elem = fs.closure.elems.find(path);
             if (elem == fs.closure.elems.end())
-                throw Error(format("bad closure, missing path '%1%'") % path);
+                throw Error(format("bad closure, missing path ‘%1%’") % path);
 
             for (StringSet::const_iterator i = elem->second.refs.begin();
                  i != elem->second.refs.end(); ++i)
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index 4e5c99bffa5978b3bfa2e963ad1c2a47a55fa9e8..63e20a8c77a7a33d2a90035148b089b9933419d7 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -52,7 +52,7 @@ static Path useDeriver(Path path)
     if (isDerivation(path)) return path;
     Path drvPath = store->queryPathInfo(path)->deriver;
     if (drvPath == "")
-        throw Error(format("deriver of path '%1%' is not known") % path);
+        throw Error(format("deriver of path ‘%1%’ is not known") % path);
     return drvPath;
 }
 
@@ -77,7 +77,7 @@ static PathSet realisePath(Path path, bool build = true)
         for (auto & j : p.second) {
             DerivationOutputs::iterator i = drv.outputs.find(j);
             if (i == drv.outputs.end())
-                throw Error(format("derivation '%1%' does not have an output named '%2%'") % p.first % j);
+                throw Error(format("derivation ‘%1%’ does not have an output named ‘%2%’") % p.first % j);
             Path outPath = i->second.path;
             if (store2) {
                 if (gcRoot == "")
@@ -96,7 +96,7 @@ static PathSet realisePath(Path path, bool build = true)
 
     else {
         if (build) store->ensurePath(path);
-        else if (!store->isValidPath(path)) throw Error(format("path '%1%' does not exist and cannot be created") % path);
+        else if (!store->isValidPath(path)) throw Error(format("path ‘%1%’ does not exist and cannot be created") % path);
         if (store2) {
             if (gcRoot == "")
                 printGCWarning();
@@ -125,7 +125,7 @@ static void opRealise(Strings opFlags, Strings opArgs)
         else if (i == "--check") buildMode = bmCheck;
         else if (i == "--hash") buildMode = bmHash;
         else if (i == "--ignore-unknown") ignoreUnknown = true;
-        else throw UsageError(format("unknown flag '%1%'") % i);
+        else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     Paths paths;
     for (auto & i : opArgs) {
@@ -182,7 +182,7 @@ static void opAddFixed(Strings opFlags, Strings opArgs)
 
     for (auto & i : opFlags)
         if (i == "--recursive") recursive = true;
-        else throw UsageError(format("unknown flag '%1%'") % i);
+        else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     if (opArgs.empty())
         throw UsageError("first argument must be hash algorithm");
@@ -202,10 +202,10 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
 
     for (auto i : opFlags)
         if (i == "--recursive") recursive = true;
-        else throw UsageError(format("unknown flag '%1%'") % i);
+        else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     if (opArgs.size() != 3)
-        throw UsageError(format("'--print-fixed-path' requires three arguments"));
+        throw UsageError(format("‘--print-fixed-path’ requires three arguments"));
 
     Strings::iterator i = opArgs.begin();
     HashType hashAlgo = parseHashType(*i++);
@@ -307,9 +307,9 @@ static void opQuery(Strings opFlags, Strings opArgs)
         else if (i == "--use-output" || i == "-u") useOutput = true;
         else if (i == "--force-realise" || i == "--force-realize" || i == "-f") forceRealise = true;
         else if (i == "--include-outputs") includeOutputs = true;
-        else throw UsageError(format("unknown flag '%1%'") % i);
+        else throw UsageError(format("unknown flag ‘%1%’") % i);
         if (prev != qDefault && prev != query)
-            throw UsageError(format("query type '%1%' conflicts with earlier flag") % i);
+            throw UsageError(format("query type ‘%1%’ conflicts with earlier flag") % i);
     }
 
     if (query == qDefault) query = qOutputs;
@@ -367,7 +367,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
                 Derivation drv = store->derivationFromPath(path);
                 StringPairs::iterator j = drv.env.find(bindingName);
                 if (j == drv.env.end())
-                    throw Error(format("derivation '%1%' has no environment binding named '%2%'")
+                    throw Error(format("derivation ‘%1%’ has no environment binding named ‘%2%’")
                         % path % bindingName);
                 cout << format("%1%\n") % j->second;
             }
@@ -453,7 +453,7 @@ static string shellEscape(const string & s)
 static void opPrintEnv(Strings opFlags, Strings opArgs)
 {
     if (!opFlags.empty()) throw UsageError("unknown flag");
-    if (opArgs.size() != 1) throw UsageError("'--print-env' requires one derivation store path");
+    if (opArgs.size() != 1) throw UsageError("‘--print-env’ requires one derivation store path");
 
     Path drvPath = opArgs.front();
     Derivation drv = store->derivationFromPath(drvPath);
@@ -484,7 +484,7 @@ static void opReadLog(Strings opFlags, Strings opArgs)
 
     // FIXME: move getting logs into Store.
     auto store2 = std::dynamic_pointer_cast<LocalFSStore>(store);
-    if (!store2) throw Error(format("store '%s' does not support reading logs") % store->getUri());
+    if (!store2) throw Error(format("store ‘%s’ does not support reading logs") % store->getUri());
 
     for (auto & i : opArgs) {
         Path path = useDeriver(store->followLinksToStorePath(i));
@@ -533,7 +533,7 @@ static void opReadLog(Strings opFlags, Strings opArgs)
             }
         }
 
-        if (!found) throw Error(format("build log of derivation '%1%' is not available") % path);
+        if (!found) throw Error(format("build log of derivation ‘%1%’ is not available") % path);
     }
 }
 
@@ -590,7 +590,7 @@ static void opRegisterValidity(Strings opFlags, Strings opArgs)
     for (auto & i : opFlags)
         if (i == "--reregister") reregister = true;
         else if (i == "--hash-given") hashGiven = true;
-        else throw UsageError(format("unknown flag '%1%'") % i);
+        else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     if (!opArgs.empty()) throw UsageError("no arguments expected");
 
@@ -604,7 +604,7 @@ static void opCheckValidity(Strings opFlags, Strings opArgs)
 
     for (auto & i : opFlags)
         if (i == "--print-invalid") printInvalid = true;
-        else throw UsageError(format("unknown flag '%1%'") % i);
+        else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     for (auto & i : opArgs) {
         Path path = store->followLinksToStorePath(i);
@@ -612,7 +612,7 @@ static void opCheckValidity(Strings opFlags, Strings opArgs)
             if (printInvalid)
                 cout << format("%1%\n") % path;
             else
-                throw Error(format("path '%1%' is not valid") % path);
+                throw Error(format("path ‘%1%’ is not valid") % path);
         }
     }
 }
@@ -636,7 +636,7 @@ static void opGC(Strings opFlags, Strings opArgs)
             long long maxFreed = getIntArg<long long>(*i, i, opFlags.end(), true);
             options.maxFreed = maxFreed >= 0 ? maxFreed : 0;
         }
-        else throw UsageError(format("bad sub-operation '%1%' in GC") % *i);
+        else throw UsageError(format("bad sub-operation ‘%1%’ in GC") % *i);
 
     if (!opArgs.empty()) throw UsageError("no arguments expected");
 
@@ -667,7 +667,7 @@ static void opDelete(Strings opFlags, Strings opArgs)
 
     for (auto & i : opFlags)
         if (i == "--ignore-liveness") options.ignoreLiveness = true;
-        else throw UsageError(format("unknown flag '%1%'") % i);
+        else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     for (auto & i : opArgs)
         options.pathsToDelete.insert(store->followLinksToStorePath(i));
@@ -706,7 +706,7 @@ static void opRestore(Strings opFlags, Strings opArgs)
 static void opExport(Strings opFlags, Strings opArgs)
 {
     for (auto & i : opFlags)
-        throw UsageError(format("unknown flag '%1%'") % i);
+        throw UsageError(format("unknown flag ‘%1%’") % i);
 
     FdSink sink(STDOUT_FILENO);
     store->exportPaths(opArgs, sink);
@@ -716,7 +716,7 @@ static void opExport(Strings opFlags, Strings opArgs)
 static void opImport(Strings opFlags, Strings opArgs)
 {
     for (auto & i : opFlags)
-        throw UsageError(format("unknown flag '%1%'") % i);
+        throw UsageError(format("unknown flag ‘%1%’") % i);
 
     if (!opArgs.empty()) throw UsageError("no arguments expected");
 
@@ -751,7 +751,7 @@ static void opVerify(Strings opFlags, Strings opArgs)
     for (auto & i : opFlags)
         if (i == "--check-contents") checkContents = true;
         else if (i == "--repair") repair = true;
-        else throw UsageError(format("unknown flag '%1%'") % i);
+        else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     if (store->verifyStore(checkContents, repair)) {
         printError("warning: not all errors were fixed");
@@ -770,14 +770,14 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
 
     for (auto & i : opArgs) {
         Path path = store->followLinksToStorePath(i);
-        printMsg(lvlTalkative, format("checking path '%1%'...") % path);
+        printMsg(lvlTalkative, format("checking path ‘%1%’...") % path);
         auto info = store->queryPathInfo(path);
         HashSink sink(info->narHash.type);
         store->narFromPath(path, sink);
         auto current = sink.finish();
         if (current.first != info->narHash) {
             printError(
-                format("path '%1%' was modified! expected hash '%2%', got '%3%'")
+                format("path ‘%1%’ was modified! expected hash ‘%2%’, got ‘%3%’")
                 % path % printHash(info->narHash) % printHash(current.first));
             status = 1;
         }
@@ -816,7 +816,7 @@ static void opServe(Strings opFlags, Strings opArgs)
     bool writeAllowed = false;
     for (auto & i : opFlags)
         if (i == "--write") writeAllowed = true;
-        else throw UsageError(format("unknown flag '%1%'") % i);
+        else throw UsageError(format("unknown flag ‘%1%’") % i);
 
     if (!opArgs.empty()) throw UsageError("no arguments expected");
 
@@ -979,7 +979,7 @@ static void opServe(Strings opFlags, Strings opArgs)
 static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs)
 {
     for (auto & i : opFlags)
-        throw UsageError(format("unknown flag '%1%'") % i);
+        throw UsageError(format("unknown flag ‘%1%’") % i);
 
     if (opArgs.size() != 3) throw UsageError("three arguments expected");
     auto i = opArgs.begin();
diff --git a/src/nix/cat.cc b/src/nix/cat.cc
index a35f640d8840118d22fa974c6b1576748e4fda4f..2405a8cb44efdb2c1de01a9cfb9ea6bbefb4f33a 100644
--- a/src/nix/cat.cc
+++ b/src/nix/cat.cc
@@ -13,9 +13,9 @@ struct MixCat : virtual Args
     {
         auto st = accessor->stat(path);
         if (st.type == FSAccessor::Type::tMissing)
-            throw Error(format("path '%1%' does not exist") % path);
+            throw Error(format("path ‘%1%’ does not exist") % path);
         if (st.type != FSAccessor::Type::tRegular)
-            throw Error(format("path '%1%' is not a regular file") % path);
+            throw Error(format("path ‘%1%’ is not a regular file") % path);
 
         std::cout << accessor->readFile(path);
     }
diff --git a/src/nix/command.cc b/src/nix/command.cc
index 0a903a6b85fef7692fd574e9dba779ed3c614f31..5a8288da912f34d24e94df0451a28d97ea99100f 100644
--- a/src/nix/command.cc
+++ b/src/nix/command.cc
@@ -27,7 +27,7 @@ MultiCommand::MultiCommand(const Commands & _commands)
         assert(!command);
         auto i = commands.find(ss.front());
         if (i == commands.end())
-            throw UsageError(format("'%1%' is not a recognised command") % ss.front());
+            throw UsageError(format("‘%1%’ is not a recognised command") % ss.front());
         command = i->second;
     }});
 }
@@ -54,7 +54,7 @@ void MultiCommand::printHelp(const string & programName, std::ostream & out)
     printTable(out, table);
 
     out << "\n";
-    out << "For full documentation, run 'man " << programName << "' or 'man " << programName << "-<COMMAND>'.\n";
+    out << "For full documentation, run ‘man " << programName << "’ or ‘man " << programName << "-<COMMAND>’.\n";
 }
 
 bool MultiCommand::processFlag(Strings::iterator & pos, Strings::iterator end)
@@ -95,7 +95,7 @@ void StorePathsCommand::run(ref<Store> store)
 {
     if (all) {
         if (storePaths.size())
-            throw UsageError("'--all' does not expect arguments");
+            throw UsageError("‘--all’ does not expect arguments");
         for (auto & p : store->queryAllValidPaths())
             storePaths.push_back(p);
     }
diff --git a/src/nix/command.hh b/src/nix/command.hh
index 780102c67f9fc36d26dc15a02aae1a97fe901cef..a29cdcf7f50f3366a7f4cb740a22af08f8cd4a3e 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -59,7 +59,7 @@ public:
 typedef std::map<std::string, ref<Command>> Commands;
 
 /* An argument parser that supports multiple subcommands,
-   i.e. '<command> <subcommand>'. */
+   i.e. ‘<command> <subcommand>’. */
 class MultiCommand : virtual Args
 {
 public:
diff --git a/src/nix/copy.cc b/src/nix/copy.cc
index f342c0ef31d7dccd7619e4e30f44d8dbe0174443..e8317dc393fdb51dba898ef32672f1d6709d3345 100644
--- a/src/nix/copy.cc
+++ b/src/nix/copy.cc
@@ -41,7 +41,7 @@ struct CmdCopy : StorePathsCommand
     void run(ref<Store> store, Paths storePaths) override
     {
         if (srcUri.empty() && dstUri.empty())
-            throw UsageError("you must pass '--from' and/or '--to'");
+            throw UsageError("you must pass ‘--from’ and/or ‘--to’");
 
         ref<Store> srcStore = srcUri.empty() ? store : openStore(srcUri);
         ref<Store> dstStore = dstUri.empty() ? store : openStore(dstUri);
@@ -63,7 +63,7 @@ struct CmdCopy : StorePathsCommand
                 checkInterrupt();
 
                 if (!dstStore->isValidPath(storePath)) {
-                    Activity act(*logger, lvlInfo, format("copying '%s'...") % storePath);
+                    Activity act(*logger, lvlInfo, format("copying ‘%s’...") % storePath);
 
                     copyStorePath(srcStore, dstStore, storePath);
 
diff --git a/src/nix/hash.cc b/src/nix/hash.cc
index 615aa9b4671698e2b9e6acda88a4e57bcc897b0c..5dd891e8add31d192892cd876a5a5d1f2670c09c 100644
--- a/src/nix/hash.cc
+++ b/src/nix/hash.cc
@@ -107,7 +107,7 @@ static int compatNixHash(int argc, char * * argv)
             string s = getArg(*arg, arg, end);
             ht = parseHashType(s);
             if (ht == htUnknown)
-                throw UsageError(format("unknown hash type '%1%'") % s);
+                throw UsageError(format("unknown hash type ‘%1%’") % s);
         }
         else if (*arg == "--to-base16") op = opTo16;
         else if (*arg == "--to-base32") op = opTo32;
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index 074534bce2656400cf42851333454454cca7e047..8341bbc5a3a41a4bed3336a75639471501f5a147 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -74,7 +74,7 @@ UserEnvElems MixInstallables::evalInstallables(ref<Store> store)
             }
 
             else
-                throw UsageError(format("don't know what to do with '%1%'") % installable);
+                throw UsageError(format("don't know what to do with ‘%1%’") % installable);
         }
 
         else {
diff --git a/src/nix/installables.hh b/src/nix/installables.hh
index a90d738681cfc6f85e31cf4d4f5f2d90248f516f..a58f7dc59bb446454d1113d637bac426a7a6ec1f 100644
--- a/src/nix/installables.hh
+++ b/src/nix/installables.hh
@@ -38,9 +38,9 @@ struct MixInstallables : virtual Args
     UserEnvElems evalInstallables(ref<Store> store);
 
     /* Return a value representing the Nix expression from which we
-       are installing. This is either the file specified by '--file',
-       or an attribute set constructed from $NIX_PATH, e.g. '{ nixpkgs
-       = import ...; bla = import ...; }'. */
+       are installing. This is either the file specified by ‘--file’,
+       or an attribute set constructed from $NIX_PATH, e.g. ‘{ nixpkgs
+       = import ...; bla = import ...; }’. */
     Value * buildSourceExpr(EvalState & state);
 
 };
diff --git a/src/nix/ls.cc b/src/nix/ls.cc
index 2c9bd8dd75cf4df8821fd26eb122d347e70de59a..3476dfb052873b1fba91c49266c5be2146f148f9 100644
--- a/src/nix/ls.cc
+++ b/src/nix/ls.cc
@@ -63,7 +63,7 @@ struct MixLs : virtual Args
 
         auto st = accessor->stat(path);
         if (st.type == FSAccessor::Type::tMissing)
-            throw Error(format("path '%1%' does not exist") % path);
+            throw Error(format("path ‘%1%’ does not exist") % path);
         doPath(st, path,
             st.type == FSAccessor::Type::tDirectory ? "." : baseNameOf(path),
             showDirectory);
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 578a663cf397a08ed635672085ddbb57cfdef8a6..a30031ad07b45767c702057f533d6a48e2d4a598 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -71,15 +71,15 @@ struct CmdRun : StoreCommand, MixInstallables
                 createDirs(tmpDir + store->storeDir);
 
                 if (mount(store2->realStoreDir.c_str(), (tmpDir + store->storeDir).c_str(), "", MS_BIND, 0) == -1)
-                    throw SysError(format("mounting '%s' on '%s'") % store2->realStoreDir % store->storeDir);
+                    throw SysError(format("mounting ‘%s’ on ‘%s’") % store2->realStoreDir % store->storeDir);
 
                 for (auto entry : readDirectory("/")) {
                     Path dst = tmpDir + "/" + entry.name;
                     if (pathExists(dst)) continue;
                     if (mkdir(dst.c_str(), 0700) == -1)
-                        throw SysError(format("creating directory '%s'") % dst);
+                        throw SysError(format("creating directory ‘%s’") % dst);
                     if (mount(("/" + entry.name).c_str(), dst.c_str(), "", MS_BIND | MS_REC, 0) == -1)
-                        throw SysError(format("mounting '%s' on '%s'") %  ("/" + entry.name) % dst);
+                        throw SysError(format("mounting ‘%s’ on ‘%s’") %  ("/" + entry.name) % dst);
                 }
 
                 char * cwd = getcwd(0, 0);
@@ -87,19 +87,19 @@ struct CmdRun : StoreCommand, MixInstallables
                 Finally freeCwd([&]() { free(cwd); });
 
                 if (chroot(tmpDir.c_str()) == -1)
-                    throw SysError(format("chrooting into '%s'") % tmpDir);
+                    throw SysError(format("chrooting into ‘%s’") % tmpDir);
 
                 if (chdir(cwd) == -1)
-                    throw SysError(format("chdir to '%s' in chroot") % cwd);
+                    throw SysError(format("chdir to ‘%s’ in chroot") % cwd);
             } else
                 if (mount(store2->realStoreDir.c_str(), store->storeDir.c_str(), "", MS_BIND, 0) == -1)
-                    throw SysError(format("mounting '%s' on '%s'") % store2->realStoreDir % store->storeDir);
+                    throw SysError(format("mounting ‘%s’ on ‘%s’") % store2->realStoreDir % store->storeDir);
 
             writeFile("/proc/self/setgroups", "deny");
             writeFile("/proc/self/uid_map", (format("%d %d %d") % uid % uid % 1).str());
             writeFile("/proc/self/gid_map", (format("%d %d %d") % gid % gid % 1).str());
 #else
-            throw Error(format("mounting the Nix store on '%s' is not supported on this platform") % store->storeDir);
+            throw Error(format("mounting the Nix store on ‘%s’ is not supported on this platform") % store->storeDir);
 #endif
         }
 
@@ -119,7 +119,7 @@ struct CmdRun : StoreCommand, MixInstallables
         setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1);
 
         if (execlp("bash", "bash", nullptr) == -1)
-            throw SysError("unable to exec 'bash'");
+            throw SysError("unable to exec ‘bash’");
     }
 };
 
diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc
index 333c434ee0c11f920e395326c98372a4f93d89c8..d8d8c0f53df0576695d31e2209a77b09656f7a60 100644
--- a/src/nix/sigs.cc
+++ b/src/nix/sigs.cc
@@ -30,7 +30,7 @@ struct CmdCopySigs : StorePathsCommand
     void run(ref<Store> store, Paths storePaths) override
     {
         if (substituterUris.empty())
-            throw UsageError("you must specify at least one substituter using '-s'");
+            throw UsageError("you must specify at least one substituter using ‘-s’");
 
         // FIXME: factor out commonality with MixVerify.
         std::vector<ref<Store>> substituters;
@@ -45,7 +45,7 @@ struct CmdCopySigs : StorePathsCommand
         logger->setExpected(doneLabel, storePaths.size());
 
         auto doPath = [&](const Path & storePath) {
-            Activity act(*logger, lvlInfo, format("getting signatures for '%s'") % storePath);
+            Activity act(*logger, lvlInfo, format("getting signatures for ‘%s’") % storePath);
 
             checkInterrupt();
 
@@ -112,7 +112,7 @@ struct CmdSignPaths : StorePathsCommand
     void run(ref<Store> store, Paths storePaths) override
     {
         if (secretKeyFile.empty())
-            throw UsageError("you must specify a secret key file using '-k'");
+            throw UsageError("you must specify a secret key file using ‘-k’");
 
         SecretKey secretKey(readFile(secretKeyFile));
 
diff --git a/src/nix/verify.cc b/src/nix/verify.cc
index afb7fa16cf2c92fb7594f6a264d97d4fe0f1e3d1..2f8d02fa060e07807ca17e87eb998d38bd1a5ffe 100644
--- a/src/nix/verify.cc
+++ b/src/nix/verify.cc
@@ -73,7 +73,7 @@ struct CmdVerify : StorePathsCommand
             try {
                 checkInterrupt();
 
-                Activity act(*logger, lvlInfo, format("checking '%s'") % storePath);
+                Activity act(*logger, lvlInfo, format("checking ‘%s’") % storePath);
 
                 auto info = store->queryPathInfo(storePath);
 
@@ -88,7 +88,7 @@ struct CmdVerify : StorePathsCommand
                         logger->incProgress(corruptedLabel);
                         corrupted = 1;
                         printError(
-                            format("path '%s' was modified! expected hash '%s', got '%s'")
+                            format("path ‘%s’ was modified! expected hash ‘%s’, got ‘%s’")
                             % info->path % printHash(info->narHash) % printHash(hash.first));
                     }
 
@@ -139,7 +139,7 @@ struct CmdVerify : StorePathsCommand
                     if (!good) {
                         logger->incProgress(untrustedLabel);
                         untrusted++;
-                        printError(format("path '%s' is untrusted") % info->path);
+                        printError(format("path ‘%s’ is untrusted") % info->path);
                     }
 
                 }
diff --git a/src/resolve-system-dependencies/resolve-system-dependencies.cc b/src/resolve-system-dependencies/resolve-system-dependencies.cc
index a0a368f8a9edd96aee3b433746636ed5726adc60..ae8ca36ba9deac519e98eb05f5b0f87bfcc588a0 100644
--- a/src/resolve-system-dependencies/resolve-system-dependencies.cc
+++ b/src/resolve-system-dependencies/resolve-system-dependencies.cc
@@ -62,13 +62,13 @@ std::set<std::string> runResolver(const Path & filename) {
             }
         }
         if (mach64_offset == 0) {
-            printError(format("Could not find any mach64 blobs in file '%1%', continuing...") % filename);
+            printError(format("Could not find any mach64 blobs in file ‘%1%’, continuing...") % filename);
             return std::set<string>();
         }
     } else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) {
         mach64_offset = 0;
     } else {
-        printError(format("Object file has unknown magic number '%1%', skipping it...") % magic);
+        printError(format("Object file has unknown magic number ‘%1%’, skipping it...") % magic);
         return std::set<string>();
     }
 
@@ -97,7 +97,7 @@ std::set<std::string> runResolver(const Path & filename) {
 bool isSymlink(const Path & path) {
     struct stat st;
     if(lstat(path.c_str(), &st))
-        throw SysError(format("getting attributes of path '%1%'") % path);
+        throw SysError(format("getting attributes of path ‘%1%’") % path);
 
     return S_ISLNK(st.st_mode);
 }
diff --git a/tests/common.sh.in b/tests/common.sh.in
index 3862aafcf670fb3b00000bd4fcc096226056c34c..4565a490adfd4220a5ffc189df065485200f49f2 100644
--- a/tests/common.sh.in
+++ b/tests/common.sh.in
@@ -66,7 +66,7 @@ clearCacheCache() {
 
 startDaemon() {
     # Start the daemon, wait for the socket to appear.  !!!
-    # 'nix-daemon' should have an option to fork into the background.
+    # ‘nix-daemon’ should have an option to fork into the background.
     rm -f $NIX_STATE_DIR/daemon-socket/socket
     nix-daemon &
     for ((i = 0; i < 30; i++)); do
diff --git a/tests/lang/imported.nix b/tests/lang/imported.nix
index f5c790293ff4fba2af4890538276d5f509a46df6..fb39ee4efacd5d3c530f5011871947bb5667bac7 100644
--- a/tests/lang/imported.nix
+++ b/tests/lang/imported.nix
@@ -1,3 +1,3 @@
-# The function 'range' comes from lib.nix and was added to the lexical
+# The function ‘range’ comes from lib.nix and was added to the lexical
 # scope by scopedImport.
 range 1 5 ++ import ./imported2.nix
diff --git a/tests/multiple-outputs.sh b/tests/multiple-outputs.sh
index 068bd20b149e424eae588549e9e444919ce309bb..7ac77908151cfda34a8655b69212e6c4869155cf 100644
--- a/tests/multiple-outputs.sh
+++ b/tests/multiple-outputs.sh
@@ -3,7 +3,7 @@ source common.sh
 clearStore
 
 # Test whether read-only evaluation works when referring to the
-# 'drvPath' attribute.
+# ‘drvPath’ attribute.
 echo "evaluating c..."
 #drvPath=$(nix-instantiate multiple-outputs.nix -A c --readonly-mode)
 
@@ -14,7 +14,7 @@ drvPath=$(nix-instantiate multiple-outputs.nix -A c)
 grep -q 'multiple-outputs-a.drv",\["first","second"\]' $drvPath
 grep -q 'multiple-outputs-b.drv",\["out"\]' $drvPath
 
-# While we're at it, test the 'unsafeDiscardOutputDependency' primop.
+# While we're at it, test the ‘unsafeDiscardOutputDependency’ primop.
 outPath=$(nix-build multiple-outputs.nix -A d --no-out-link)
 drvPath=$(cat $outPath/drv)
 outPath=$(nix-store -q $drvPath)
diff --git a/tests/nix-copy-closure.nix b/tests/nix-copy-closure.nix
index 177714839ca744ef58bb8a601e063fc27ef173e1..44126dd64e47193b076863813b77bd12785c7d2f 100644
--- a/tests/nix-copy-closure.nix
+++ b/tests/nix-copy-closure.nix
@@ -1,4 +1,4 @@
-# Test 'nix-copy-closure'.
+# Test ‘nix-copy-closure’.
 
 { system, nix }:
 
diff --git a/tests/timeout.builder.sh b/tests/timeout.builder.sh
index 7e72fe1a8c59618656e2ae45be403df2b62a9261..3fbdd57946ad4583a22e4440e6839bbd8fe5b168 100644
--- a/tests/timeout.builder.sh
+++ b/tests/timeout.builder.sh
@@ -1,2 +1,2 @@
-echo "'timeout' builder entering an infinite loop"
+echo "‘timeout’ builder entering an infinite loop"
 while true ; do echo -n .; done
diff --git a/tests/timeout.sh b/tests/timeout.sh
index 7d8f4daea560d864d82d7f03a2445757a0e8f50c..2ebd06b9330cf48508bb8770137bcc99a1525845 100644
--- a/tests/timeout.sh
+++ b/tests/timeout.sh
@@ -5,7 +5,7 @@ source common.sh
 failed=0
 messages="`nix-build -Q timeout.nix --timeout 2 2>&1 || failed=1`"
 if [ $failed -ne 0 ]; then
-    echo "error: 'nix-store' succeeded; should have timed out"
+    echo "error: ‘nix-store’ succeeded; should have timed out"
     exit 1
 fi
 
diff --git a/tests/user-envs.sh b/tests/user-envs.sh
index 18d9cf7626321208f763dea1717c8c14d57043a5..c4192fdc59b2bdffbb6ec34a251a93b102171d79 100644
--- a/tests/user-envs.sh
+++ b/tests/user-envs.sh
@@ -164,7 +164,7 @@ nix-env -q '*' | grep -q bar-0.1.1
 
 # Test priorities: foo-0.1 has a lower priority than foo-1.0, so it
 # should be possible to install both without a collision.  Also test
-# '--set-flag priority' to manually override the declared priorities.
+# ‘--set-flag priority’ to manually override the declared priorities.
 nix-env -e '*'
 nix-env -i foo-0.1 foo-1.0
 [ "$($profiles/test/bin/foo)" = "foo-1.0" ]