[Sciviews-commits] r240 - in pkg/svIDE: . R man
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Tue Dec 29 12:14:31 CET 2009
Author: phgrosjean
Date: 2009-12-29 12:14:28 +0100 (Tue, 29 Dec 2009)
New Revision: 240
Added:
pkg/svIDE/R/kpfTranslate.R
pkg/svIDE/man/kpfTranslate.Rd
Modified:
pkg/svIDE/DESCRIPTION
pkg/svIDE/NAMESPACE
pkg/svIDE/NEWS
Log:
Komodo projects/packages translation function using poEdit added in svIDE
Modified: pkg/svIDE/DESCRIPTION
===================================================================
--- pkg/svIDE/DESCRIPTION 2009-12-28 15:25:20 UTC (rev 239)
+++ pkg/svIDE/DESCRIPTION 2009-12-29 11:14:28 UTC (rev 240)
@@ -2,10 +2,10 @@
Type: Package
Title: SciViews GUI API - IDE and code editor functions
Depends: R (>= 2.6.0)
-Imports: utils, tcltk, svMisc
+Imports: utils, tcltk, svMisc, XML
Description: Function for the GUI API to interact with external IDE/code editors
-Version: 0.9-47
-Date: 2009-10-26
+Version: 0.9-48
+Date: 2009-12-29
Author: Philippe Grosjean
Maintainer: Philippe Grosjean <phgrosjean at sciviews.org>
License: GPL (>= 2)
Modified: pkg/svIDE/NAMESPACE
===================================================================
--- pkg/svIDE/NAMESPACE 2009-12-28 15:25:20 UTC (rev 239)
+++ pkg/svIDE/NAMESPACE 2009-12-29 11:14:28 UTC (rev 240)
@@ -1,4 +1,4 @@
-import(utils, tcltk, svMisc)
+import(utils, tcltk, svMisc, XML)
export(createCallTipFile,
createSyntaxFile,
@@ -7,4 +7,8 @@
guiCallTip,
guiComplete,
guiDDEInstall,
- Source)
+ Source,
+ kpf2pot,
+ kpz2pot,
+ kpfTranslate,
+ kpzTranslate)
Modified: pkg/svIDE/NEWS
===================================================================
--- pkg/svIDE/NEWS 2009-12-28 15:25:20 UTC (rev 239)
+++ pkg/svIDE/NEWS 2009-12-29 11:14:28 UTC (rev 240)
@@ -1,5 +1,12 @@
= svIDE News
+== Changes in svIDE 0.9-48
+
+* Addition of kpf2pot(), kpz2pot(), kpfTranslate() and kpzTranslate() to allow
+ translation of Komodo project or package using poEdit. Introduces a new
+ dependency on XML R package on CRAN.
+
+
== Changes in svIDE 0.9-47
* guiComplete now does not have a givetype argument any more. Extra information
Added: pkg/svIDE/R/kpfTranslate.R
===================================================================
--- pkg/svIDE/R/kpfTranslate.R (rev 0)
+++ pkg/svIDE/R/kpfTranslate.R 2009-12-29 11:14:28 UTC (rev 240)
@@ -0,0 +1,270 @@
+# Make a .pot file with translatable strings found in a Komodo project/package
+# Translatable strings are:
+# 1) All names
+# 2) In snippets:
+# [[%ask:R-desc:XXX]]
+# [[%ask:R-tip:XXX]]
+# [[%ask|pref:URL-help:XXX]] and [[%ask|pref:RWiki-help:XXX]]
+# [[%tr:XXX]
+# 3) In macros:
+# Strings inside _("XXX"), with _() being a function returning its argument
+kpf2pot <- function (kpfFile, potFile) {
+ if (missing(potFile))
+ potFile <- sub("\\.kpf", ".pot", kpfFile)
+ if (kpfFile == potFile)
+ potFile <- paste(kpfFile, "pot", sep = ".")
+ # Extract translatable strings from this file
+ doc <- xmlRoot(xmlTreeParse(kpfFile))
+ imax <- xmlSize(doc)
+ if (imax < 1) stop("No node found in the file!")
+ # Collect all strings to be translated
+ s <- character(0)
+ for (i in 1:imax) {
+ n <- xmlGetAttr(doc[[i]], "name")
+ if (!is.null(n)) {
+ s <- c(s, n)
+ type <- xmlName(doc[[i]])
+ # If this is a snippet, look for other translatable strings
+ if (type == "snippet") {
+ snip <- xmlValue(doc[[i]])
+ chunks <- strsplit(snip, "\\[\\[|\\]\\]")[[1]]
+ # Keep only chunks starting with R-desc:, R-tip:, URL-help:
+ # RWiki-help: or %tr:
+ chunks <- chunks[grep("^%ask:R-desc:|^%ask:R-tip:|^%ask:URL-help:|^%ask:RWiki-help:|^%pref:URL-help|^%pref:RWiki-help|%tr:", chunks)]
+ # Are there any remaining chunks?
+ l <- length(chunks)
+ if (l > 0) {
+ # Eliminate leading stuff
+ chunks <- sub("^%ask:[^:]+:|%tr:", "", chunks)
+ # and add to the list of items to translate
+ s <- c(s, chunks)
+ }
+ } else if (type == "macro") {
+ mac <- xmlValue(doc[[i]])
+ # Collect tagged strings (i.e., strings inside _(...))
+ repeat {
+ str <- sub("^.*_\\(\"(.*[^\\\\])\"\\).*$", "\\1", mac)
+ if (str == mac) break
+ s <- c(s, gsub('\\\\"', '"', str))
+ mac <- sub("^(.*)(_\\(\".*[^\\\\]\"\\))(.*)$",
+ "\\1(...)\\3", mac)
+ }
+ repeat {
+ str <- sub("^.*_\\('(.*[^\\\\])'\\).*$", "\\1", mac)
+ if (str == mac) break
+ s <- c(s, gsub("\\\\'", "'", str))
+ mac <- sub("^(.*)(_\\('.*[^\\\\]'\\))(.*)$",
+ "\\1(...)\\3", mac)
+ }
+ }
+ }
+ }
+ # Keep only unique strings
+ s <- unique(s)
+ s <- s[nzchar(s)]
+ tmp <- shQuote(encodeString(s), type = "cmd")
+ con <- file(potFile, "wt")
+ on.exit(close(con))
+ writeLines(con = con, c("msgid \"\"", "msgstr \"\"",
+ sprintf("\"Project-Id-Version: R %s.%s\\n\"",
+ R.version$major, R.version$minor),
+ "\"Report-Msgid-Bugs-To: support at sciviews.org\\n\"",
+ paste("\"POT-Creation-Date: ", format(Sys.time(), "%Y-%m-%d %H:%M"),
+ "\\n\"", sep = ""),
+ "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"",
+ "\"Last-Translator: FULL NAME <EMAIL at ADDRESS>\\n\"",
+ "\"Language-Team: LANGUAGE <LL at li.org>\\n\"",
+ "\"MIME-Version: 1.0\\n\"",
+ "\"Content-Type: text/plain; charset=utf-8\\n\"",
+ "\"Content-Transfer-Encoding: 8bit\\n\"",
+ ""))
+ for (e in tmp)
+ writeLines(con = con, c("", paste("msgid", e), "msgstr \"\""))
+ # Check that the .pot file is created
+ return(invisible(file.exists(potFile)))
+}
+
+kpz2pot <- function (kpzFile, potFile) {
+ if (missing(potFile))
+ potFile <- sub("\\.kpz", ".pot", kpzFile)
+ if (kpzFile == potFile)
+ potFile <- paste(kpzFile, "pot", sep = ".")
+ # The kpz file is a zipped file containing package.kpf in a subdirectory
+ f <- file.path(tempdir(), "package.kpf")
+ unlink(f) # Make sure the file does not exist yet
+ unzip(kpzFile, junkpaths = TRUE, exdir = tempdir())
+ if (!file.exists(file.path(tempdir(), "package.kpf")))
+ stop("Impossible to extract the content of the .kpz file.")
+ # Run kpf2pot() on this file
+ kpf2pot(f, potFile)
+ # Delete extracted file
+ unlink(f)
+ # Check that the .pot file is created
+ return(invisible(file.exists(potFile)))
+}
+
+kpfTranslate <- function (kpfFile, lang, poFile, kpf2File) {
+ if (missing(lang))
+ stop("You must provide 'lang' (ex.: 'fr', or 'de')")
+ po <- paste("-", lang, ".po", sep = "")
+ kpf2 <- paste("-", lang, ".kpf", sep = "")
+ if (missing(poFile))
+ poFile <- sub("\\.kpf", po, kpfFile)
+ if (kpfFile == poFile)
+ poFile <- paste(kpfFile, po, sep = "")
+ if (!file.exists(poFile))
+ stop("'poFile' not found!")
+ if (missing(kpf2File)) {
+ kpf2File <- sub("\\.kpf", kpf2, kpfFile)
+ if (kpfFile == kpf2File)
+ kpf2File <- paste(kpfFile, kpf2, sep = "")
+ unlink(kpf2File) # Make sure we create a new resulting file
+ }
+
+ # Read the content of the .po file
+ tr <- readLines(poFile, encoding = "UTF-8")
+ # Keep only lines starting with msgid or msgstr
+ trid <- tr[regexpr("^msgid ", tr) == 1]
+ trid <- sub("^msgid ", "", trid)
+ trmsg <- tr[regexpr("^msgstr ", tr) == 1]
+ trmsg <- sub("^msgstr ", "", trmsg)
+ # Check that both trid and trmsg have same length
+ if (length(trid) != length(trmsg))
+ stop("Unequal number of id and translated strings in the .po file!")
+ keep <- trid != "\"\""
+ trid <- trid[keep]
+ trmsg <- trmsg[keep]
+
+ # We need to "unquote" the strings
+ unquote <- function (s) {
+ # Replace any \\\" by \"
+ s <- gsub("\\\\\"", "\"", s)
+ # Eliminate leading and trailing quotes
+ s <- sub("^\"", "", s)
+ s <- sub("\"$", "", s)
+ return(s)
+ }
+ trid <- unquote(trid)
+ trmsg <- unquote(trmsg)
+ names(trmsg) <- trid
+
+ # Extract translatable strings from the .kpf file
+ doc <- xmlRoot(xmlTreeParse(kpfFile))
+ imax <- xmlSize(doc)
+ if (imax < 1) stop("No node found in the file!")
+ # Collect all strings to be translated
+ trans <- function (s) {
+ tr <- as.character(trmsg[s])
+ if (is.na(tr) || tr == "") return(s) else return(tr)
+ }
+
+ s <- character(0)
+ for (i in 1:imax) {
+ n <- xmlGetAttr(doc[[i]], "name")
+ if (!is.null(n)) {
+ # Replace name in attributes of this node
+ node <- addAttributes(doc[[i]], name = trans(n), append = TRUE)
+ type <- xmlName(node)
+ # If this is a snippet, look for other translatable strings
+ if (type == "snippet") {
+ snip <- xmlValue(node)
+ chunks <- strsplit(snip, "\\[\\[|\\]\\]")[[1]]
+ # Translate chunks starting with R-desc:, R-tip:, URL-help:,
+ # RWiki-help: or %tr:
+ toTrans <- grep("^%ask:R-desc:|^%ask:R-tip:|^%ask:URL-help:|^%ask:RWiki-help:|^%pref:URL-help|^%pref:RWiki-help|%tr:", chunks)
+ if (length(toTrans) > 0) {
+ for (j in toTrans) {
+ msg <- sub("^%ask:[^:]+:|%tr:", "", chunks[j])
+ header <- sub("^(%ask:[^:]+:|%tr:).*$", "\\1", chunks[j])
+ chunks[j] <- paste(header, trans(msg), sep = "")
+ }
+ # Reconstitute the snippet content using translated messages
+ snip <- paste(chunks, c("[[", "]]"),
+ sep = "", collapse = "")
+ # We need to eliminate latest '[['
+ snip <- sub("\\[\\[$", "", snip)
+ xmlValue(node) <- snip
+ }
+ } else if (type == "macro") {
+ mac <- xmlValue(node)
+ # Translate tagged strings (i.e., strings inside _(...))
+ repeat {
+ str <- sub("^.*_\\(\"(.*[^\\\\])\"\\).*$", "\\1", mac)
+ if (str == mac) break
+ s <- trans(gsub('\\\\"', '"', str))
+ s <- gsub('"', '\\"', s)
+ mac <- sub("^(.*)(_\\(\".*[^\\\\]\"\\))(.*)$",
+ paste("\\1%%%%%%(\"", s, "\")\\3", sep = ""), mac)
+ }
+ repeat {
+ str <- sub("^.*_\\('(.*[^\\\\])'\\).*$", "\\1", mac)
+ if (str == mac) break
+ s <- trans(gsub("\\\\'", "'", str))
+ s <- gsub("'", "\\'", s)
+ mac <- sub("^(.*)(_\\('.*[^\\\\]'\\))(.*)$",
+ paste("\\1%%%%%%('", s, "')\\3", sep = ""), mac)
+ }
+ mac <- gsub("%%%%%%", "_", mac)
+ xmlValue(node) <- mac
+ }
+ # Replace the node with its translated version
+ doc[[i]] <- node
+ }
+ }
+ # In case the project has a name, we change it now
+ projname <- xmlGetAttr(doc, "name")
+ if (!is.null(projname))
+ doc <- addAttributes(doc, name = basename(kpf2File), append = TRUE)
+
+ # Save the translated XML content into the second .kpf file
+ saveXML(doc, file = kpf2File, prefix = '<?xml version="1.0" encoding="UTF-8"?>\n<!-- Komodo Project File - DO NOT EDIT -->\n')
+ # Check that the new .kpf file is produced
+ return(invisible(file.exists(kpf2File)))
+}
+
+kpzTranslate <- function (kpzFile, lang, poFile, kpz2File) {
+ if (missing(lang))
+ stop("You must provide 'lang' (ex.: 'fr', or 'de')")
+ po <- paste("-", lang, ".po", sep = "")
+ kpz2 <- paste("-", lang, ".kpz", sep = "")
+ if (missing(poFile))
+ poFile <- sub("\\.kpz", po, kpzFile)
+ if (kpzFile == poFile)
+ poFile <- paste(kpzFile, po, sep = "")
+ if (!file.exists(poFile))
+ stop("'poFile' not found!")
+ if (missing(kpz2File))
+ kpz2File <- sub("\\.kpz", kpz2, kpzFile)
+ if (kpzFile == kpz2File)
+ kpz2File <- paste(kpzFile, kpz2, sep = "")
+ unlink(kpz2File) # Make sure we create a new resulting file
+
+ # The kpz file is a zipped file containing package.kpf in a subdirectory
+ f <- file.path(tempdir(), "package.kpf")
+ unlink(f) # Make sure the file does not exist yet
+ unzip(kpzFile, junkpaths = TRUE, exdir = tempdir())
+ if (!file.exists(file.path(tempdir(), "package.kpf")))
+ stop("Impossible to extract the content of the .kpz file.")
+
+ # Call kpfTranslate on the created package.kpf file
+ kpfTranslate(f, lang, poFile, f)
+
+ # Compress the file in a kpz zipped archive named kpz2File
+ # Create a directory of the same name as the package
+ d <- sub("\\\\.kpz$", "", basename(kpz2File))
+ d <- file.path(dirname(f), d)
+ dir.create(d)
+ # Move the package.kpf file there
+ f2 <- file.path(d, "package.kpf")
+ file.copy(f, f2)
+ unlink(f)
+ # Compress (zip) the directory
+ odir <- getwd()
+ on.exit(setwd(odir))
+ setwd(dirname(kpz2File))
+ # Note: the 'zip' program must be accessible!
+ cmd <- paste('zip -rqm9 "', basename(kpz2File), '" "', d, '"', sep = "")
+ try(system(cmd, intern = TRUE, wait = TRUE), silent = TRUE)
+ # Check that the file is produced
+ return(invisible(file.exists(kpz2File)))
+}
Added: pkg/svIDE/man/kpfTranslate.Rd
===================================================================
--- pkg/svIDE/man/kpfTranslate.Rd (rev 0)
+++ pkg/svIDE/man/kpfTranslate.Rd 2009-12-29 11:14:28 UTC (rev 240)
@@ -0,0 +1,112 @@
+\name{kpfTranslate}
+\alias{kpf2pot}
+\alias{kpz2pot}
+\alias{kpfTranslate}
+\alias{kpzTranslate}
+
+\title{ Create a POT file or use a PO file to allow translating Komodo project (.kpf) or package (.kpz) }
+
+\description{
+ Komodo Edit/IDE snippets are static elements and do not allow to use translation
+ facilites easily. The \code{kpX2pot()} and \code{kpXTranslate()} functions
+ provide a mechanism to use poEdit, a program designed to translate strings for
+ software to ease and automatise translation of Komodo projets or packages (see details section).
+}
+
+\usage{
+kpf2pot(kpfFile, potFile)
+kpz2pot(kpzFile, potFile)
+kpfTranslate(kpfFile, lang, poFile, kpf2File)
+kpzTranslate(kpzFile, lang, poFile, kpz2File)
+}
+
+\arguments{
+ \item{kpfFile}{ A Komodo project file with a .kpf extension to be translated }
+ \item{kpzFile}{ A Komodo package file with a .kpz extension to be translated }
+ \item{potFile}{ The name of a .pot file providing strings to be translated,
+ if not provided, it is the same name as the .kpf/.kpz file, but with a .pot
+ extension instead }
+ \item{lang}{ The language to translate to, for instance, 'fr' for French,
+ 'de' for German, 'it' for Italian, 'en_GB' for Great Britain's English, etc. }
+ \item{poFile}{ The path to the .po file containing the translations. If not
+ provided, it is assumed to be the basename of the .kpf/.kpz file without
+ extension, plus '-' and lang and with a .po extension in the same directory
+ as the .kpf/.kpz file. For instance, the default translation file for
+ \code{myproject.kpf} into French is named \code{myproject-fr.po}. }
+ \item{kpf2File}{ The Komodo project file to create with the translation. If
+ not provided, it is assumed to be the same as the initial project file, but
+ with '-' and lang appended to the base name. For instance, the French
+ translation of \code{myproject.kpf} would be \code{myproject-fr.kpf} in the
+ same directory, by default. }
+ \item{kpz2File}{ Same as kpf2File, but for Komodo package files with a .kpz
+ extension. }
+}
+\value{
+ These functions return invisibly \code{TRUE} if the targetted file is create,
+ or \code{FALSE} otherwise.
+}
+
+\details{
+ Komodo Edit/IDE are code editor programs that can be used to edit R code
+ efficiently with the SciViews-K plugin (see http://www.sciviews.org/SciViews-K).
+ Komodo can be customized by using projects files (by project customization) with
+ a .kpf extension, or tools collected together in the toolbox and that can be
+ saved on disk in Komodo package files with a .kpz extension.
+
+ Among the tools you can place in a Komodo project or package, there are macros
+ (written in JavaScript or Python). Thanks to the SciViews-K plugin, you have
+ access to R and R code inside these macros. This makes it a good candidated for
+ writing GUI elements, including dialog boxes, on top of your favorite R code
+ editor. You can also add 'snippets' in those projects/packages. Snippets are
+ short pieces of code, including R code, you can save and retrieve easily. In the
+ snippets, you can define replaceable parts, includings parts you replace after
+ prompting the user with a dialog box. SciViews uses these features extensively,
+ for instance, for the 'R reference' toolbox.
+
+ Unfortunately, theses tools do not benefit easily from translation features. So,
+ it is hard to maintain the same project/package in different languages. The
+ functions provided here ease the maintenance of such projects/packages translated
+ in various languages. Here is how you can use them:
+
+ 1) Save your Komodo project or package on disk.
+
+ 2) Use the \code{kpX2pot()} function to create, or update the .pot file. This
+ file lists all translatable strings found in the project/package. Translatable
+ strings are: (a) names of tools or folders, (b) items in snippets that are
+ flagged with \%ask:R-desc:, \%ask:R-tip:, \%ask:URL-help:, \%ask:RWiki-help:,
+ \%pref:URL-help:, \%pref:RWiki-help, and \%tr: (see Komodo help to learn how to
+ use these tags in snippets), and (c) strings in JavaScript macros that are
+ flagged with \code{_()}. For instance, creating a .pot file for
+ \code{~/myproject.kpf} is as simple as calling \code{kpf2pot("~/myproject.kpf")}.
+
+ 3) Use the poEdit program (search Google to find, download and install this
+ free Open Source translation utility, if you don't have it yet) to translate
+ the extracted strings. The first time, you create a .po file based on the .pot
+ template you just created. For subsequent versions of your project/package, you
+ reuse the old .po file and select menu entry 'Catalog -> Update from POT file...'
+ to update your translation file with new strings found in the .pot file. You
+ are better to place the .po file in the same directory as your project/package
+ and to give it the same name, but replacing .kpX by -<lang>.po, where <lang>
+ is the language in which you do the translation. You can distribute .pot files
+ to a staff of translators that would send you back the created/modified .po
+ files for compilation. See the poEdit documentation for further help (note that
+ multiline strings and singular/plural forms are not supported yet).
+
+ 4) Once you have your .po file ready, you can translate your Komodo project/package
+ in that language easily from R. For instance, a project file \code{~/myproject.kpf}
+ can be translated in French, using the .po file \code{~/myproject-fr.po} that
+ contains French translation of your strings by issuing in R
+ \code{kpfTranslate("~/myproject.kpf", "fr")}. That produces a \code{~/myproject-fr.kpf}
+ file that contains your Komodo project translated in French. Please, note that
+ \code{kpzTranslate()} currently needs to access the external \code{zip} program
+ for zipping the .kpz file. This program is usually accessible from within Linux
+ or Mac OS X by default, but needs to be installed (and made accessible through
+ the PATH) under Windows.
+
+ 5) To open your translated project/package in Komodo, just drag and drop the new
+ file on the central area of the Komodo window.
+}
+
+\author{ Philippe Grosjean <phgrosjean at sciviews.org> }
+
+\keyword{ utilities }
More information about the Sciviews-commits
mailing list