From cc2a53507fad06c3b4c5a7370f1179fcef21bd11 Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Mon, 1 Nov 2021 07:31:25 -0500
Subject: [PATCH 01/19] Export dev_compile()

This function was previously called `update_mo_files()`. I don't know if `dev_compile()` is better, but I like the idea of using prefixes to distinguish between functions for developers and translators. Let me know if you have a better name, or if you'd prefer me to leave as is.

I also made a few changes to make it more user friendly: it now discovers the package name (if needed), and can lazily recompile just the files that have changed. I also tweaked the messaging so you get one message per translation (which makes it easier to see what the msgfmt messages apply to).

Two questions:

* Is my scoped use of roxygen2 ok? (roxygen2 is designed to work like this so there's no chance of it clobbering your hand written files)

* Do you want me to add tests? If so, I'd probably start by refactoring the code to extract out a data frame (data table?) that contains the po path, mo_path, and language.
---
 DESCRIPTION                             |  1 +
 NAMESPACE                               |  2 ++
 R/msgmerge.R                            | 48 +++++++++++++++++++------
 R/translate_package.R                   |  3 +-
 R/utils.R                               | 11 ++++++
 man/dev_compile.Rd                      | 24 +++++++++++++
 tests/testthat/test-translate-package.R |  2 +-
 7 files changed, 77 insertions(+), 14 deletions(-)
 create mode 100644 man/dev_compile.Rd

diff --git a/DESCRIPTION b/DESCRIPTION
index 32f2369a..f7c659fa 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -14,3 +14,4 @@ URL: https://github.com/MichaelChirico/potools
 BugReports: https://github.com/MichaelChirico/potools/issues
 Encoding: UTF-8
 VignetteBuilder: knitr
+RoxygenNote: 7.1.2
diff --git a/NAMESPACE b/NAMESPACE
index cfcc50ca..cf831cff 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -11,6 +11,8 @@ export(translate_package)
 export(get_message_data)
 export(write_po_file, po_metadata)
 
+export(dev_compile)
+
 export(check_cracked_messages, check_untranslated_cat, check_untranslated_src)
 
 export(check_potools_sys_reqs)
diff --git a/R/msgmerge.R b/R/msgmerge.R
index 1b703618..58563c87 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -15,6 +15,10 @@ run_msgmerge = function(po_file, pot_file) {
 
 run_msgfmt = function(po_file, mo_file, verbose) {
   use_stats <- if (verbose) '--statistics' else ''
+
+  po_file <- path.expand(po_file)
+  mo_file <- path.expand(mo_file)
+
   # See #218. Solaris msgfmt doesn't support -c or --statistics
   if (Sys.info()[["sysname"]] == "SunOS") {
     cmd = sprintf("msgfmt -o %s %s", shQuote(mo_file), shQuote(po_file)) # nocov
@@ -31,21 +35,43 @@ run_msgfmt = function(po_file, mo_file, verbose) {
   return(invisible())
 }
 
-update_mo_files = function(dir, package, verbose) {
-  inst_dir <- file.path(dir, "inst", "po")
+#' Compile `.po` files to `.mo`
+#'
+#' This function compiles the plain text `.po` files that translators work
+#' to the binary `.mo` files that are installed with packages. In order for
+#' translations to be accessible to R, you must re-compile every time the `.po`
+#' files are changed.
+#'
+#' @param dir Path to package root directory.
+#' @param package Name of package. If not supplied, read from `DESCRIPTION`.
+#' @param verbose If `TRUE`, print information as it goes.
+#' @param lazy If `TRUE`, only `.mo` functions that are older than `.po`
+#'   files be updated
+dev_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
+  if (is.null(package)) {
+    package <- get_desc_data(dir)[["Package"]]
+  }
+
+  po_paths <- list.files(file.path(dir, "po"), pattern = "\\.po$", full.names = TRUE)
+
   lang_regex <- "^(R-)?([a-zA-Z_]+)\\.po$"
+  languages <- gsub(lang_regex, "\\2", basename(po_paths))
+  mo_names <- gsub(lang_regex, sprintf("\\1%s.mo", package), basename(po_paths))
+  mo_paths <- file.path(dir, "inst", "po", languages, "LC_MESSAGES", mo_names)
+  dir_create(dirname(mo_paths))
 
-  po_files <- list.files(file.path(dir, "po"), pattern = "\\.po$")
-  languages <- gsub(lang_regex, "\\2", po_files)
-  mo_files <- gsub(lang_regex, sprintf("\\1%s.mo", package), po_files)
-  mo_dirs <- file.path(inst_dir, languages, "LC_MESSAGES")
-  # NB: dir.create() only accepts one directory at a time...
-  for (mo_dir in unique(mo_dirs)) dir.create(mo_dir, recursive = TRUE, showWarnings = FALSE)
+  if (lazy) {
+    outdated <- is_outdated(po_paths, mo_paths)
+    po_paths <- po_paths[outdated]
+    mo_paths <- mo_paths[outdated]
+    languages <- languages[outdated]
+  }
 
-  for (ii in seq_along(po_files)) {
+  for (ii in seq_along(po_paths)) {
+    if (verbose) message("Recompiling ", languages[ii], " translation")
     run_msgfmt(
-      po_file = file.path(dir, "po", po_files[ii]),
-      mo_file = file.path(mo_dirs[ii], mo_files[ii]),
+      po_file = po_paths[ii],
+      mo_file = mo_paths[ii],
       verbose = verbose
     )
   }
diff --git a/R/translate_package.R b/R/translate_package.R
index beee713f..9460aee9 100644
--- a/R/translate_package.R
+++ b/R/translate_package.R
@@ -211,9 +211,8 @@ translate_package = function(
     INCOMPLETE = FALSE
   }
 
-  if (verbose) message('"Installing" translations with msgfmt')
   # TODO: reinstate source marker tags, at least for src .pot file & maybe for R .pot file too?
-  update_mo_files(dir, package, verbose = verbose)
+  dev_compile(dir, package, verbose = verbose)
   return(invisible())
 }
 
diff --git a/R/utils.R b/R/utils.R
index 8875f902..4b101a6b 100644
--- a/R/utils.R
+++ b/R/utils.R
@@ -153,3 +153,14 @@ get_lang_metadata = function(language) {
   }
   update_metadata(language)
 }
+
+# Vectorised version of dir.create
+dir_create <- function(dirs) {
+  for (dir in unique(dirs)) {
+    dir.create(dir, recursive = TRUE, showWarnings = FALSE)
+  }
+}
+
+is_outdated <- function(src, dst) {
+  ifelse(!file.exists(dst), TRUE, file.mtime(src) > file.mtime(dst))
+}
diff --git a/man/dev_compile.Rd b/man/dev_compile.Rd
new file mode 100644
index 00000000..7cd450dc
--- /dev/null
+++ b/man/dev_compile.Rd
@@ -0,0 +1,24 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/msgmerge.R
+\name{dev_compile}
+\alias{dev_compile}
+\title{Compile `.po` files to `.mo`}
+\usage{
+dev_compile(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE)
+}
+\arguments{
+\item{dir}{Path to package root directory.}
+
+\item{package}{Name of package. If not supplied, read from `DESCRIPTION`.}
+
+\item{lazy}{If `TRUE`, only `.mo` functions that are older than `.po`
+files be updated}
+
+\item{verbose}{If `TRUE`, print information as it goes.}
+}
+\description{
+This function compiles the plain text `.po` files that translators work
+to the binary `.mo` files that are installed with packages. In order for
+translations to be accessible to R, you must re-compile every time the `.po`
+files are changed.
+}
diff --git a/tests/testthat/test-translate-package.R b/tests/testthat/test-translate-package.R
index ce2535e7..4fa187e5 100644
--- a/tests/testthat/test-translate-package.R
+++ b/tests/testthat/test-translate-package.R
@@ -69,7 +69,7 @@ test_that("translate_package works on a simple package", {
     {
       expect_messages(
         translate_package(pkg, "zh_CN", verbose=TRUE),
-        c("Beginning new translations", "BEGINNING TRANSLATION", '"Installing" translations with msgfmt'),
+        c("Beginning new translations", "BEGINNING TRANSLATION", "Generating en@quot translations"),
         fixed = TRUE
       )
 

From 3a28abbea1fc0a950e3f01c5b11467760b0bbefc Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Thu, 4 Nov 2021 08:04:43 -0500
Subject: [PATCH 02/19] Rename dev_compile() to po_compile()

---
 NAMESPACE                             |  2 +-
 R/msgmerge.R                          |  9 ++++-----
 R/translate_package.R                 |  2 +-
 man/{dev_compile.Rd => po_compile.Rd} | 13 ++++++-------
 4 files changed, 12 insertions(+), 14 deletions(-)
 rename man/{dev_compile.Rd => po_compile.Rd} (63%)

diff --git a/NAMESPACE b/NAMESPACE
index cf831cff..04e6750d 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -11,7 +11,7 @@ export(translate_package)
 export(get_message_data)
 export(write_po_file, po_metadata)
 
-export(dev_compile)
+export(po_compile)
 
 export(check_cracked_messages, check_untranslated_cat, check_untranslated_src)
 
diff --git a/R/msgmerge.R b/R/msgmerge.R
index 58563c87..1a09157d 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -37,17 +37,16 @@ run_msgfmt = function(po_file, mo_file, verbose) {
 
 #' Compile `.po` files to `.mo`
 #'
-#' This function compiles the plain text `.po` files that translators work
-#' to the binary `.mo` files that are installed with packages. In order for
-#' translations to be accessible to R, you must re-compile every time the `.po`
-#' files are changed.
+#' This function compiles the plain text `.po` files that translators work with
+#' in to the binary `.mo` files that are installed with packages and used for
+#' live translations.
 #'
 #' @param dir Path to package root directory.
 #' @param package Name of package. If not supplied, read from `DESCRIPTION`.
 #' @param verbose If `TRUE`, print information as it goes.
 #' @param lazy If `TRUE`, only `.mo` functions that are older than `.po`
 #'   files be updated
-dev_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
+po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
   if (is.null(package)) {
     package <- get_desc_data(dir)[["Package"]]
   }
diff --git a/R/translate_package.R b/R/translate_package.R
index 9460aee9..fd7bc0cc 100644
--- a/R/translate_package.R
+++ b/R/translate_package.R
@@ -212,7 +212,7 @@ translate_package = function(
   }
 
   # TODO: reinstate source marker tags, at least for src .pot file & maybe for R .pot file too?
-  dev_compile(dir, package, verbose = verbose)
+  po_compile(dir, package, verbose = verbose)
   return(invisible())
 }
 
diff --git a/man/dev_compile.Rd b/man/po_compile.Rd
similarity index 63%
rename from man/dev_compile.Rd
rename to man/po_compile.Rd
index 7cd450dc..59803d1b 100644
--- a/man/dev_compile.Rd
+++ b/man/po_compile.Rd
@@ -1,10 +1,10 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/msgmerge.R
-\name{dev_compile}
-\alias{dev_compile}
+\name{po_compile}
+\alias{po_compile}
 \title{Compile `.po` files to `.mo`}
 \usage{
-dev_compile(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE)
+po_compile(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE)
 }
 \arguments{
 \item{dir}{Path to package root directory.}
@@ -17,8 +17,7 @@ files be updated}
 \item{verbose}{If `TRUE`, print information as it goes.}
 }
 \description{
-This function compiles the plain text `.po` files that translators work
-to the binary `.mo` files that are installed with packages. In order for
-translations to be accessible to R, you must re-compile every time the `.po`
-files are changed.
+This function compiles the plain text `.po` files that translators work with
+in to the binary `.mo` files that are installed with packages and used for
+live translations.
 }

From a9872991353c3c7780280c155006962d988cede1 Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Thu, 4 Nov 2021 08:31:28 -0500
Subject: [PATCH 03/19] Pull out separate po_files() function

---
 R/msgmerge.R | 40 +++++++++++++++++++++++++---------------
 1 file changed, 25 insertions(+), 15 deletions(-)

diff --git a/R/msgmerge.R b/R/msgmerge.R
index 1a09157d..dbe49a4b 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -47,6 +47,22 @@ run_msgfmt = function(po_file, mo_file, verbose) {
 #' @param lazy If `TRUE`, only `.mo` functions that are older than `.po`
 #'   files be updated
 po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
+  po_files <- po_files(dir = dir, package = package, lazy = lazy)
+  dir_create(dirname(po_files$mo))
+
+  for (ii in seq_len(nrow(po_files))) {
+    if (verbose) messagef("Recompiling %s translation", po_files$language[ii])
+    run_msgfmt(
+      po_file = po_files$po[ii],
+      mo_file = po_files$mo[ii],
+      verbose = verbose
+    )
+  }
+
+  return(invisible())
+}
+
+po_files <- function(dir = ".", package = NULL, lazy = TRUE) {
   if (is.null(package)) {
     package <- get_desc_data(dir)[["Package"]]
   }
@@ -57,25 +73,19 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
   languages <- gsub(lang_regex, "\\2", basename(po_paths))
   mo_names <- gsub(lang_regex, sprintf("\\1%s.mo", package), basename(po_paths))
   mo_paths <- file.path(dir, "inst", "po", languages, "LC_MESSAGES", mo_names)
-  dir_create(dirname(mo_paths))
 
-  if (lazy) {
-    outdated <- is_outdated(po_paths, mo_paths)
-    po_paths <- po_paths[outdated]
-    mo_paths <- mo_paths[outdated]
-    languages <- languages[outdated]
-  }
+  out <- data.frame(
+    language = languages,
+    po = po_paths,
+    mo = mo_paths,
+    stringsAsFactors = FALSE
+  )
 
-  for (ii in seq_along(po_paths)) {
-    if (verbose) message("Recompiling ", languages[ii], " translation")
-    run_msgfmt(
-      po_file = po_paths[ii],
-      mo_file = mo_paths[ii],
-      verbose = verbose
-    )
+  if (lazy) {
+    out <- out[is_outdated(out$po, out$mo), , drop = FALSE]
   }
 
-  return(invisible())
+  out
 }
 
 update_en_quot_mo_files <- function(dir, verbose) {

From 428171894c6a86819aa7a94628a59bcaa1655b7a Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Thu, 4 Nov 2021 08:31:41 -0500
Subject: [PATCH 04/19] If not lazy, delete .mo files without matching .po

---
 R/msgmerge.R | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/R/msgmerge.R b/R/msgmerge.R
index dbe49a4b..a907d50c 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -50,6 +50,17 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
   po_files <- po_files(dir = dir, package = package, lazy = lazy)
   dir_create(dirname(po_files$mo))
 
+  if (!lazy) {
+    # Clear out all older translations
+    mo_dirs <- dir(file.path(dir, "inst", "po"), full.names = TRUE)
+    to_delete <- mo_dirs[!basename(mo_dirs) %in% c(po_files$language, "en@quot")]
+
+    for (dir in to_delete) {
+      if (verbose) messagef("Deleting unmatched %s translation", basename(dir))
+      unlink(dir, recursive = TRUE)
+    }
+  }
+
   for (ii in seq_len(nrow(po_files))) {
     if (verbose) messagef("Recompiling %s translation", po_files$language[ii])
     run_msgfmt(

From 51e1f70f8006f652a1eba9847344260617d5fbb2 Mon Sep 17 00:00:00 2001
From: Michael Chirico <michaelchirico4@gmail.com>
Date: Sat, 6 Nov 2021 14:36:25 -0700
Subject: [PATCH 05/19] typo

---
 R/msgmerge.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/msgmerge.R b/R/msgmerge.R
index a907d50c..923595b5 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -38,7 +38,7 @@ run_msgfmt = function(po_file, mo_file, verbose) {
 #' Compile `.po` files to `.mo`
 #'
 #' This function compiles the plain text `.po` files that translators work with
-#' in to the binary `.mo` files that are installed with packages and used for
+#' into the binary `.mo` files that are installed with packages and used for
 #' live translations.
 #'
 #' @param dir Path to package root directory.

From 2122d917943879b54198145a6f4bb81e7465ceef Mon Sep 17 00:00:00 2001
From: Michael Chirico <michaelchirico4@gmail.com>
Date: Sat, 6 Nov 2021 14:41:32 -0700
Subject: [PATCH 06/19] simplify helper

---
 R/utils.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/utils.R b/R/utils.R
index 4b101a6b..ffa6cacd 100644
--- a/R/utils.R
+++ b/R/utils.R
@@ -162,5 +162,5 @@ dir_create <- function(dirs) {
 }
 
 is_outdated <- function(src, dst) {
-  ifelse(!file.exists(dst), TRUE, file.mtime(src) > file.mtime(dst))
+  !file.exists(dst) | (file.mtime(src) > file.mtime(dst))
 }

From 0426052a64aeb755e1f2dc3269e9feda3d92c811 Mon Sep 17 00:00:00 2001
From: Michael Chirico <michaelchirico4@gmail.com>
Date: Sat, 6 Nov 2021 14:49:05 -0700
Subject: [PATCH 07/19] tweaks

---
 R/msgmerge.R | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/R/msgmerge.R b/R/msgmerge.R
index 923595b5..e6dc5dbb 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -80,20 +80,19 @@ po_files <- function(dir = ".", package = NULL, lazy = TRUE) {
 
   po_paths <- list.files(file.path(dir, "po"), pattern = "\\.po$", full.names = TRUE)
 
-  lang_regex <- "^(R-)?([a-zA-Z_]+)\\.po$"
+  lang_regex <- "^(R-)?([a-z]{2}(?:_[A-Z]{2})?)\\.po$"
   languages <- gsub(lang_regex, "\\2", basename(po_paths))
   mo_names <- gsub(lang_regex, sprintf("\\1%s.mo", package), basename(po_paths))
   mo_paths <- file.path(dir, "inst", "po", languages, "LC_MESSAGES", mo_names)
 
-  out <- data.frame(
+  out <- data.table(
     language = languages,
     po = po_paths,
-    mo = mo_paths,
-    stringsAsFactors = FALSE
+    mo = mo_paths
   )
 
   if (lazy) {
-    out <- out[is_outdated(out$po, out$mo), , drop = FALSE]
+    out <- out[is_outdated(po, mo)]
   }
 
   out

From 1250bff4e3b6176c419283c3ab8cf02da42f2e95 Mon Sep 17 00:00:00 2001
From: Michael Chirico <michaelchirico4@gmail.com>
Date: Sat, 6 Nov 2021 14:49:50 -0700
Subject: [PATCH 08/19] match signature order

---
 R/msgmerge.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/msgmerge.R b/R/msgmerge.R
index e6dc5dbb..ba6cf5cf 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -43,9 +43,9 @@ run_msgfmt = function(po_file, mo_file, verbose) {
 #'
 #' @param dir Path to package root directory.
 #' @param package Name of package. If not supplied, read from `DESCRIPTION`.
-#' @param verbose If `TRUE`, print information as it goes.
 #' @param lazy If `TRUE`, only `.mo` functions that are older than `.po`
 #'   files be updated
+#' @param verbose If `TRUE`, print information as it goes.
 po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
   po_files <- po_files(dir = dir, package = package, lazy = lazy)
   dir_create(dirname(po_files$mo))

From 013b749f5ddf2a56dcac15711af7d3d0cdc9ef20 Mon Sep 17 00:00:00 2001
From: Michael Chirico <michaelchirico4@gmail.com>
Date: Sat, 6 Nov 2021 14:58:24 -0700
Subject: [PATCH 09/19] clarify verbose message

---
 R/msgmerge.R | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/R/msgmerge.R b/R/msgmerge.R
index ba6cf5cf..94f6ea91 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -56,7 +56,10 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
     to_delete <- mo_dirs[!basename(mo_dirs) %in% c(po_files$language, "en@quot")]
 
     for (dir in to_delete) {
-      if (verbose) messagef("Deleting unmatched %s translation", basename(dir))
+      if (verbose) messagef(
+        "Found a compiled translation for %s at %s, but no corresponding .po; deleting",
+        basename(dir), dirname(dir)
+      )
       unlink(dir, recursive = TRUE)
     }
   }

From 28ab5b44b018ece6d59fb21a08af83e88c8c3267 Mon Sep 17 00:00:00 2001
From: Michael Chirico <michaelchirico4@gmail.com>
Date: Sat, 6 Nov 2021 15:01:42 -0700
Subject: [PATCH 10/19] rename po_files --> get_po_metadata

feels less muddled for describing the output (which involves .mo files)
---
 R/msgmerge.R | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/R/msgmerge.R b/R/msgmerge.R
index 94f6ea91..7b1a3fa2 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -47,13 +47,13 @@ run_msgfmt = function(po_file, mo_file, verbose) {
 #'   files be updated
 #' @param verbose If `TRUE`, print information as it goes.
 po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
-  po_files <- po_files(dir = dir, package = package, lazy = lazy)
-  dir_create(dirname(po_files$mo))
+  po_metadata <- get_po_metadata(dir = dir, package = package, lazy = lazy)
+  dir_create(dirname(po_metadata$mo))
 
   if (!lazy) {
     # Clear out all older translations
     mo_dirs <- dir(file.path(dir, "inst", "po"), full.names = TRUE)
-    to_delete <- mo_dirs[!basename(mo_dirs) %in% c(po_files$language, "en@quot")]
+    to_delete <- mo_dirs[!basename(mo_dirs) %in% c(po_metadata$language, "en@quot")]
 
     for (dir in to_delete) {
       if (verbose) messagef(
@@ -64,11 +64,11 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
     }
   }
 
-  for (ii in seq_len(nrow(po_files))) {
-    if (verbose) messagef("Recompiling %s translation", po_files$language[ii])
+  for (ii in seq_len(nrow(po_metadata))) {
+    if (verbose) messagef("Recompiling %s translation", po_metadata$language[ii])
     run_msgfmt(
-      po_file = po_files$po[ii],
-      mo_file = po_files$mo[ii],
+      po_file = po_metadata$po[ii],
+      mo_file = po_metadata$mo[ii],
       verbose = verbose
     )
   }
@@ -76,7 +76,7 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
   return(invisible())
 }
 
-po_files <- function(dir = ".", package = NULL, lazy = TRUE) {
+get_po_metadata <- function(dir = ".", package = NULL, lazy = TRUE) {
   if (is.null(package)) {
     package <- get_desc_data(dir)[["Package"]]
   }

From 0e8f56b29d9cb6686457b8ff1be9de530b4444e5 Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Sun, 7 Nov 2021 08:16:15 -0600
Subject: [PATCH 11/19] get_po_metadata() tweaks

* Hoist lazy up into po_compile()
* Use lang-regexp for filtering files
* Record po type
---
 R/msgmerge.R | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/R/msgmerge.R b/R/msgmerge.R
index 7b1a3fa2..c6482481 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -47,10 +47,12 @@ run_msgfmt = function(po_file, mo_file, verbose) {
 #'   files be updated
 #' @param verbose If `TRUE`, print information as it goes.
 po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
-  po_metadata <- get_po_metadata(dir = dir, package = package, lazy = lazy)
+  po_metadata <- get_po_metadata(dir = dir, package = package)
   dir_create(dirname(po_metadata$mo))
 
-  if (!lazy) {
+  if (lazy) {
+    po_metadata <- po_metadata[is_outdated(po, mo)]
+  } else {
     # Clear out all older translations
     mo_dirs <- dir(file.path(dir, "inst", "po"), full.names = TRUE)
     to_delete <- mo_dirs[!basename(mo_dirs) %in% c(po_metadata$language, "en@quot")]
@@ -76,29 +78,26 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
   return(invisible())
 }
 
-get_po_metadata <- function(dir = ".", package = NULL, lazy = TRUE) {
+get_po_metadata <- function(dir = ".", package = NULL) {
   if (is.null(package)) {
     package <- get_desc_data(dir)[["Package"]]
   }
 
-  po_paths <- list.files(file.path(dir, "po"), pattern = "\\.po$", full.names = TRUE)
-
   lang_regex <- "^(R-)?([a-z]{2}(?:_[A-Z]{2})?)\\.po$"
+  po_paths <- list.files(file.path(dir, "po"), pattern = lang_regex, full.names = TRUE)
+
   languages <- gsub(lang_regex, "\\2", basename(po_paths))
+  type <- ifelse(grepl("^(R-)", basename(po_paths)), "R", "src")
+
   mo_names <- gsub(lang_regex, sprintf("\\1%s.mo", package), basename(po_paths))
   mo_paths <- file.path(dir, "inst", "po", languages, "LC_MESSAGES", mo_names)
 
-  out <- data.table(
+  data.table(
     language = languages,
+    type = type,
     po = po_paths,
     mo = mo_paths
   )
-
-  if (lazy) {
-    out <- out[is_outdated(po, mo)]
-  }
-
-  out
 }
 
 update_en_quot_mo_files <- function(dir, verbose) {

From 47a6a0838663bad6828150258d60f3e96ad06bbb Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Sun, 7 Nov 2021 08:18:11 -0600
Subject: [PATCH 12/19] Message about translation type

---
 R/msgmerge.R | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/R/msgmerge.R b/R/msgmerge.R
index c6482481..824aff78 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -67,10 +67,11 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
   }
 
   for (ii in seq_len(nrow(po_metadata))) {
-    if (verbose) messagef("Recompiling %s translation", po_metadata$language[ii])
+    row <- po_metadata[ii]
+    if (verbose) messagef("Recompiling '%s' %s translation", row$language, row$type)
     run_msgfmt(
-      po_file = po_metadata$po[ii],
-      mo_file = po_metadata$mo[ii],
+      po_file = row$po,
+      mo_file = row$mo,
       verbose = verbose
     )
   }

From fb69e90f43365af1807a5ab3c65ee32921703523 Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Sun, 7 Nov 2021 08:24:20 -0600
Subject: [PATCH 13/19] Move po_compile() to own file

---
 R/msgmerge.R      | 64 --------------------------------------------
 R/po_compile.R    | 67 +++++++++++++++++++++++++++++++++++++++++++++++
 man/po_compile.Rd |  4 +--
 potools.Rproj     |  1 +
 4 files changed, 70 insertions(+), 66 deletions(-)
 create mode 100644 R/po_compile.R

diff --git a/R/msgmerge.R b/R/msgmerge.R
index 824aff78..47c2d37b 100644
--- a/R/msgmerge.R
+++ b/R/msgmerge.R
@@ -35,71 +35,7 @@ run_msgfmt = function(po_file, mo_file, verbose) {
   return(invisible())
 }
 
-#' Compile `.po` files to `.mo`
-#'
-#' This function compiles the plain text `.po` files that translators work with
-#' into the binary `.mo` files that are installed with packages and used for
-#' live translations.
-#'
-#' @param dir Path to package root directory.
-#' @param package Name of package. If not supplied, read from `DESCRIPTION`.
-#' @param lazy If `TRUE`, only `.mo` functions that are older than `.po`
-#'   files be updated
-#' @param verbose If `TRUE`, print information as it goes.
-po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
-  po_metadata <- get_po_metadata(dir = dir, package = package)
-  dir_create(dirname(po_metadata$mo))
 
-  if (lazy) {
-    po_metadata <- po_metadata[is_outdated(po, mo)]
-  } else {
-    # Clear out all older translations
-    mo_dirs <- dir(file.path(dir, "inst", "po"), full.names = TRUE)
-    to_delete <- mo_dirs[!basename(mo_dirs) %in% c(po_metadata$language, "en@quot")]
-
-    for (dir in to_delete) {
-      if (verbose) messagef(
-        "Found a compiled translation for %s at %s, but no corresponding .po; deleting",
-        basename(dir), dirname(dir)
-      )
-      unlink(dir, recursive = TRUE)
-    }
-  }
-
-  for (ii in seq_len(nrow(po_metadata))) {
-    row <- po_metadata[ii]
-    if (verbose) messagef("Recompiling '%s' %s translation", row$language, row$type)
-    run_msgfmt(
-      po_file = row$po,
-      mo_file = row$mo,
-      verbose = verbose
-    )
-  }
-
-  return(invisible())
-}
-
-get_po_metadata <- function(dir = ".", package = NULL) {
-  if (is.null(package)) {
-    package <- get_desc_data(dir)[["Package"]]
-  }
-
-  lang_regex <- "^(R-)?([a-z]{2}(?:_[A-Z]{2})?)\\.po$"
-  po_paths <- list.files(file.path(dir, "po"), pattern = lang_regex, full.names = TRUE)
-
-  languages <- gsub(lang_regex, "\\2", basename(po_paths))
-  type <- ifelse(grepl("^(R-)", basename(po_paths)), "R", "src")
-
-  mo_names <- gsub(lang_regex, sprintf("\\1%s.mo", package), basename(po_paths))
-  mo_paths <- file.path(dir, "inst", "po", languages, "LC_MESSAGES", mo_names)
-
-  data.table(
-    language = languages,
-    type = type,
-    po = po_paths,
-    mo = mo_paths
-  )
-}
 
 update_en_quot_mo_files <- function(dir, verbose) {
   pot_files <- list.files(file.path(dir, "po"), pattern = "\\.pot$", full.names = TRUE)
diff --git a/R/po_compile.R b/R/po_compile.R
new file mode 100644
index 00000000..42eec5b4
--- /dev/null
+++ b/R/po_compile.R
@@ -0,0 +1,67 @@
+#' Compile `.po` files to `.mo`
+#'
+#' This function compiles the plain text `.po` files that translators work with
+#' into the binary `.mo` files that are installed with packages and used for
+#' live translations.
+#'
+#' @param dir Path to package root directory.
+#' @param package Name of package. If not supplied, read from `DESCRIPTION`.
+#' @param lazy If `TRUE`, only `.mo` functions that are older than `.po`
+#'   files be updated
+#' @param verbose If `TRUE`, print information as it goes.
+po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
+  po_metadata <- get_po_metadata(dir = dir, package = package)
+  dir_create(dirname(po_metadata$mo))
+
+  if (lazy) {
+    po_metadata <- po_metadata[is_outdated(po, mo)]
+  } else {
+    # Clear out all older translations
+    mo_dirs <- dir(file.path(dir, "inst", "po"), full.names = TRUE)
+    to_delete <- mo_dirs[!basename(mo_dirs) %in% c(po_metadata$language, "en@quot")]
+
+    for (dir in to_delete) {
+      if (verbose) messagef(
+        "Found a compiled translation for %s at %s, but no corresponding .po; deleting",
+        basename(dir), dirname(dir)
+      )
+      unlink(dir, recursive = TRUE)
+    }
+  }
+
+  for (ii in seq_len(nrow(po_metadata))) {
+    row <- po_metadata[ii]
+    if (verbose) messagef("Recompiling '%s' %s translation", row$language, row$type)
+    run_msgfmt(
+      po_file = row$po,
+      mo_file = row$mo,
+      verbose = verbose
+    )
+  }
+
+  return(invisible())
+}
+
+
+get_po_metadata <- function(dir = ".", package = NULL) {
+  if (is.null(package)) {
+    package <- get_desc_data(dir)[["Package"]]
+  }
+
+  lang_regex <- "^(R-)?([a-z]{2}(?:_[A-Z]{2})?)\\.po$"
+  lang_regex <- "^(R-)?([a-z]{2}(?:_[A-Z]{2})?)\\.po$"
+  po_paths <- list.files(file.path(dir, "po"), pattern = lang_regex, full.names = TRUE)
+
+  languages <- gsub(lang_regex, "\\2", basename(po_paths))
+  type <- ifelse(grepl("^(R-)", basename(po_paths)), "R", "src")
+
+  mo_names <- gsub(lang_regex, sprintf("\\1%s.mo", package), basename(po_paths))
+  mo_paths <- file.path(dir, "inst", "po", languages, "LC_MESSAGES", mo_names)
+
+  data.table(
+    language = languages,
+    type = type,
+    po = po_paths,
+    mo = mo_paths
+  )
+}
diff --git a/man/po_compile.Rd b/man/po_compile.Rd
index 59803d1b..a9ee75ca 100644
--- a/man/po_compile.Rd
+++ b/man/po_compile.Rd
@@ -1,5 +1,5 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/msgmerge.R
+% Please edit documentation in R/po_compile.R
 \name{po_compile}
 \alias{po_compile}
 \title{Compile `.po` files to `.mo`}
@@ -18,6 +18,6 @@ files be updated}
 }
 \description{
 This function compiles the plain text `.po` files that translators work with
-in to the binary `.mo` files that are installed with packages and used for
+into the binary `.mo` files that are installed with packages and used for
 live translations.
 }
diff --git a/potools.Rproj b/potools.Rproj
index 497f8bfc..9ecfdfcb 100644
--- a/potools.Rproj
+++ b/potools.Rproj
@@ -18,3 +18,4 @@ StripTrailingWhitespace: Yes
 BuildType: Package
 PackageUseDevtools: Yes
 PackageInstallArgs: --no-multiarch --with-keep.source
+PackageRoxygenize: rd

From 23f7460d13502354101f927c8a87b01768a5b094 Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Sun, 7 Nov 2021 08:34:28 -0600
Subject: [PATCH 14/19] Tweak test check

---
 tests/testthat/test-translate-package.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/testthat/test-translate-package.R b/tests/testthat/test-translate-package.R
index 4fa187e5..ed4c3b07 100644
--- a/tests/testthat/test-translate-package.R
+++ b/tests/testthat/test-translate-package.R
@@ -69,7 +69,7 @@ test_that("translate_package works on a simple package", {
     {
       expect_messages(
         translate_package(pkg, "zh_CN", verbose=TRUE),
-        c("Beginning new translations", "BEGINNING TRANSLATION", "Generating en@quot translations"),
+        c("Beginning new translations", "BEGINNING TRANSLATION", "Recompiling 'zh_CN' R translation"),
         fixed = TRUE
       )
 

From e5b8cdcd5a5a1fed65f67f08ccb4b62c2e440be4 Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Sun, 7 Nov 2021 08:36:51 -0600
Subject: [PATCH 15/19] Add a test for get_po_metadata()

---
 DESCRIPTION                      |  2 +-
 tests/testthat/test-po_compile.R | 11 +++++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)
 create mode 100644 tests/testthat/test-po_compile.R

diff --git a/DESCRIPTION b/DESCRIPTION
index f7c659fa..985fa86e 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -5,7 +5,7 @@ Version: 0.2.3
 Author: Michael Chirico
 Depends: R (>= 4.0.0)
 Imports: data.table
-Suggests: crayon, knitr, rmarkdown, testthat
+Suggests: crayon, knitr, rmarkdown, testthat, withr
 SystemRequirements: gettext
 Maintainer: Michael Chirico <MichaelChirico4@gmail.com>
 Description: Translating messages in R packages is managed using the po top-level directory and the 'gettext' program. This package provides some helper functions for building this support in R packages, e.g. common validation & I/O tasks.
diff --git a/tests/testthat/test-po_compile.R b/tests/testthat/test-po_compile.R
new file mode 100644
index 00000000..6ef6ced0
--- /dev/null
+++ b/tests/testthat/test-po_compile.R
@@ -0,0 +1,11 @@
+# metadata ----------------------------------------------------------------
+
+test_that("can find R and src translations", {
+  temp <- withr::local_tempdir()
+  dir.create(file.path(temp, "po"))
+  file.create(file.path(temp, "po", c("R-en.po", "en.po")))
+
+  meta <- withr::with_dir(temp, get_po_metadata(package = "test"))
+  expect_equal(meta$language, c("en", "en"))
+  expect_setequal(meta$type, c("R", "src"))
+})

From e5a862e3882b63bc5d758f35ba8500e38e06bef3 Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Sun, 7 Nov 2021 08:38:05 -0600
Subject: [PATCH 16/19] Improve variable access

---
 R/po_compile.R | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/R/po_compile.R b/R/po_compile.R
index 42eec5b4..8008d942 100644
--- a/R/po_compile.R
+++ b/R/po_compile.R
@@ -14,7 +14,7 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
   dir_create(dirname(po_metadata$mo))
 
   if (lazy) {
-    po_metadata <- po_metadata[is_outdated(po, mo)]
+    po_metadata <- po_metadata[is_outdated(po_metadata$po, po_metadata$mo)]
   } else {
     # Clear out all older translations
     mo_dirs <- dir(file.path(dir, "inst", "po"), full.names = TRUE)
@@ -32,11 +32,7 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
   for (ii in seq_len(nrow(po_metadata))) {
     row <- po_metadata[ii]
     if (verbose) messagef("Recompiling '%s' %s translation", row$language, row$type)
-    run_msgfmt(
-      po_file = row$po,
-      mo_file = row$mo,
-      verbose = verbose
-    )
+    run_msgfmt(row$po, row$mo, verbose = verbose)
   }
 
   return(invisible())

From 89158472f57e0f25c5f25f476a690094ef5d8265 Mon Sep 17 00:00:00 2001
From: Michael Chirico <michaelchirico4@gmail.com>
Date: Sun, 7 Nov 2021 15:11:32 -0800
Subject: [PATCH 17/19] dup line

---
 R/po_compile.R | 1 -
 1 file changed, 1 deletion(-)

diff --git a/R/po_compile.R b/R/po_compile.R
index 8008d942..26fd6691 100644
--- a/R/po_compile.R
+++ b/R/po_compile.R
@@ -44,7 +44,6 @@ get_po_metadata <- function(dir = ".", package = NULL) {
     package <- get_desc_data(dir)[["Package"]]
   }
 
-  lang_regex <- "^(R-)?([a-z]{2}(?:_[A-Z]{2})?)\\.po$"
   lang_regex <- "^(R-)?([a-z]{2}(?:_[A-Z]{2})?)\\.po$"
   po_paths <- list.files(file.path(dir, "po"), pattern = lang_regex, full.names = TRUE)
 

From 8d0cceeb6db50f6e0f79bfd6220b82b48b2f6cd6 Mon Sep 17 00:00:00 2001
From: Michael Chirico <michaelchirico4@gmail.com>
Date: Sun, 7 Nov 2021 15:26:51 -0800
Subject: [PATCH 18/19] startsWith over grepl

---
 R/po_compile.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/po_compile.R b/R/po_compile.R
index 26fd6691..5c2ec206 100644
--- a/R/po_compile.R
+++ b/R/po_compile.R
@@ -48,7 +48,7 @@ get_po_metadata <- function(dir = ".", package = NULL) {
   po_paths <- list.files(file.path(dir, "po"), pattern = lang_regex, full.names = TRUE)
 
   languages <- gsub(lang_regex, "\\2", basename(po_paths))
-  type <- ifelse(grepl("^(R-)", basename(po_paths)), "R", "src")
+  type <- ifelse(startsWith(basename(po_paths), "R-"), "R", "src")
 
   mo_names <- gsub(lang_regex, sprintf("\\1%s.mo", package), basename(po_paths))
   mo_paths <- file.path(dir, "inst", "po", languages, "LC_MESSAGES", mo_names)

From eff4ee5fb54c7526e618231699b0d487e38579c9 Mon Sep 17 00:00:00 2001
From: Hadley Wickham <h.wickham@gmail.com>
Date: Mon, 8 Nov 2021 06:19:43 -0600
Subject: [PATCH 19/19] Use new form of get_desc_data()

---
 R/po_compile.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/po_compile.R b/R/po_compile.R
index 5c2ec206..82394021 100644
--- a/R/po_compile.R
+++ b/R/po_compile.R
@@ -41,7 +41,7 @@ po_compile = function(dir = ".", package = NULL, lazy = TRUE, verbose = TRUE) {
 
 get_po_metadata <- function(dir = ".", package = NULL) {
   if (is.null(package)) {
-    package <- get_desc_data(dir)[["Package"]]
+    package <- get_desc_data(dir, "Package")
   }
 
   lang_regex <- "^(R-)?([a-z]{2}(?:_[A-Z]{2})?)\\.po$"