🎉 New script to find unused translations

This commit is contained in:
Pablo Alba 2022-10-18 22:46:41 +02:00
parent 39c601a51f
commit 47be9a21f4
10 changed files with 316 additions and 5 deletions

View file

@ -21,6 +21,7 @@
"watch-main": "shadow-cljs watch main",
"watch-test": "clojure -M:dev:shadow-cljs watch test",
"validate-translations": "node ./scripts/validate-translations.js",
"find-unused-translations": "node ./scripts/find-unused-translations.js",
"test-e2e": "cypress run",
"test-e2e-gui": "cypress open"
},

View file

@ -0,0 +1,90 @@
const fs = require('fs').promises;
const gt = require("gettext-parser");
const path = require('path');
const util = require('node:util');
const execFile = util.promisify(require('node:child_process').execFile);
async function processMsgId(msgId){
return execFile('grep', ['-r', '-o', msgId, './src'])
.catch(()=> { return msgId})
}
async function processFile(f) {
const content = await fs.readFile(f);
const data = gt.po.parse(content, "utf-8")
const translations = data.translations[''];
const badIds = [];
for (const property in translations) {
const data = await processMsgId(translations[property].msgid);
if (data!=null && data.stdout === undefined){
badIds.push(data)
}
}
return badIds;
}
async function cleanFile(f, badIds) {
console.log ("\n\nDoing automatic cleanup")
const content = await fs.readFile(f);
const data = gt.po.parse(content, "utf-8");
const translations = data.translations[''];
const keys = Object.keys(translations);
for (const key of keys) {
property = translations[key];
if (badIds.includes(property.msgid)){
console.log ('----> deleting', property.msgid)
delete data.translations[''][key];
}
}
const buff = gt.po.compile(data, {sort: true});
await fs.writeFile(f, buff);
}
async function findExecutionTimeTranslations() {
const { stdout } = await execFile('grep', ['-r', '-h', '-F', '(tr (', './src']);
console.log(stdout);
}
async function welcome() {
console.log ('####################################################################')
console.log ('# UNUSED TRANSLATIONS FINDER #')
console.log ('####################################################################')
console.log ('\n');
console.log ('DISCLAIMER: Some translations are only available at execution time.')
console.log (' This finder can\'t process them, so there can be')
console.log (' false positives.\n')
console.log (' If you want to do an automatic clean anyway,')
console.log (' call the script with:')
console.log (' npm run find-unused-translations -- --clean')
console.log (' For example:');
console.log ('--------------------------------------------------------------------');
await findExecutionTimeTranslations();
console.log ('--------------------------------------------------------------------');
}
const doCleanup = process.argv.slice(2)[0] == "--clean";
;(async () => {
await welcome();
const target = path.normalize("./translations/en.po");
const badIds = await processFile(target);
if (doCleanup){
cleanFile(target, badIds);
} else {
for (const badId of badIds){
console.log(badId);
}
}
})()

View file

@ -122,6 +122,13 @@
(let [selected? (= @selected-option type)]
[:div.export-option {:class (when selected? "selected")}
[:label.option-container
;; Execution time translation strings:
;; dashboard.export.options.all.message
;; dashboard.export.options.all.title
;; dashboard.export.options.detach.message
;; dashboard.export.options.detach.title
;; dashboard.export.options.merge.message
;; dashboard.export.options.merge.title
[:h3 (tr (str "dashboard.export.options." (d/name type) ".title"))]
[:p (tr (str "dashboard.export.options." (d/name type) ".message"))]
[:input {:type "radio"

View file

@ -67,7 +67,16 @@
[:div.attributes-stroke-row
[:div.attributes-label (tr "handoff.attributes.stroke.width")]
[:div.attributes-value (:stroke-width shape) "px"]
;; Execution time translation strings:
;; handoff.attributes.stroke.style.dotted
;; handoff.attributes.stroke.style.mixed
;; handoff.attributes.stroke.style.none
;; handoff.attributes.stroke.style.solid
[:div.attributes-value (->> stroke-style d/name (str "handoff.attributes.stroke.style.") (tr))]
;; Execution time translation strings:
;; handoff.attributes.stroke.alignment.center
;; handoff.attributes.stroke.alignment.inner
;; handoff.attributes.stroke.alignment.outer
[:div.attributes-label (->> stroke-alignment d/name (str "handoff.attributes.stroke.alignment.") (tr))]
[:& copy-button {:data (copy-stroke-data shape)}]])]))

View file

@ -142,12 +142,21 @@
(when (:text-decoration style)
[:div.attributes-unit-row
[:div.attributes-label (tr "handoff.attributes.typography.text-decoration")]
;; Execution time translation strings:
;; handoff.attributes.typography.text-decoration.none
;; handoff.attributes.typography.text-decoration.strikethrough
;; handoff.attributes.typography.text-decoration.underline
[:div.attributes-value (->> style :text-decoration (str "handoff.attributes.typography.text-decoration.") (tr))]
[:& copy-button {:data (copy-style-data style :text-decoration)}]])
(when (:text-transform style)
[:div.attributes-unit-row
[:div.attributes-label (tr "handoff.attributes.typography.text-transform")]
;; Execution time translation strings:
;; handoff.attributes.typography.text-transform.lowercase
;; handoff.attributes.typography.text-transform.none
;; handoff.attributes.typography.text-transform.titlecase
;; handoff.attributes.typography.text-transform.uppercase
[:div.attributes-value (->> style :text-transform (str "handoff.attributes.typography.text-transform.") (tr))]
[:& copy-button {:data (copy-style-data style :text-transform)}]])]))

View file

@ -45,6 +45,18 @@
[:*
[:span.tool-window-bar-icon
[:& si/element-icon {:shape first-shape}]]
;; Execution time translation strings:
;; handoff.tabs.code.selected.circle
;; handoff.tabs.code.selected.component
;; handoff.tabs.code.selected.curve
;; handoff.tabs.code.selected.frame
;; handoff.tabs.code.selected.group
;; handoff.tabs.code.selected.image
;; handoff.tabs.code.selected.mask
;; handoff.tabs.code.selected.path
;; handoff.tabs.code.selected.rect
;; handoff.tabs.code.selected.svg-raw
;; handoff.tabs.code.selected.text
[:span.tool-window-bar-title (->> selected-type d/name (str "handoff.tabs.code.selected.") (tr))]])]
[:div.tool-window-content
[:& tab-container {:on-change-tab #(do

View file

@ -103,6 +103,36 @@
[locale type multiple?]
(let [arity (if multiple? "multiple" "single")
attribute (name (or type :multiple))]
;; Execution time translation strings:
;; workspace.undo.entry.multiple.circle
;; workspace.undo.entry.multiple.color
;; workspace.undo.entry.multiple.component
;; workspace.undo.entry.multiple.curve
;; workspace.undo.entry.multiple.frame
;; workspace.undo.entry.multiple.group
;; workspace.undo.entry.multiple.media
;; workspace.undo.entry.multiple.multiple
;; workspace.undo.entry.multiple.page
;; workspace.undo.entry.multiple.path
;; workspace.undo.entry.multiple.rect
;; workspace.undo.entry.multiple.shape
;; workspace.undo.entry.multiple.text
;; workspace.undo.entry.multiple.typography
;; workspace.undo.entry.single.circle
;; workspace.undo.entry.single.color
;; workspace.undo.entry.single.component
;; workspace.undo.entry.single.curve
;; workspace.undo.entry.single.frame
;; workspace.undo.entry.single.group
;; workspace.undo.entry.single.image
;; workspace.undo.entry.single.media
;; workspace.undo.entry.single.multiple
;; workspace.undo.entry.single.page
;; workspace.undo.entry.single.path
;; workspace.undo.entry.single.rect
;; workspace.undo.entry.single.shape
;; workspace.undo.entry.single.text
;; workspace.undo.entry.single.typography
(t locale (str/format "workspace.undo.entry.%s.%s" arity attribute))))
(defn entry->message [locale entry]

View file

@ -77,6 +77,11 @@
:top (= :top dir)
:bottom (= :bottom dir))
:key (dm/str "direction-" dir)
;; Execution time translation strings:
;; workspace.options.layout.direction.bottom
;; workspace.options.layout.direction.left
;; workspace.options.layout.direction.right
;; workspace.options.layout.direction.top
:alt (tr (dm/str "workspace.options.layout.direction." (d/name dir)))
:on-click handle-on-click}
i/auto-direction]))
@ -267,6 +272,13 @@
orientation
(if (= type :packed)
;; Execution time translation strings:
;; workspace.options.layout.h.center
;; workspace.options.layout.h.left
;; workspace.options.layout.h.right
;; workspace.options.layout.v.bottom
;; workspace.options.layout.v.center
;; workspace.options.layout.v.top
(dm/str (tr (dm/str "workspace.options.layout.v." (d/name v))) ", "
(tr (dm/str "workspace.options.layout.h." (d/name h))) ", ")

View file

@ -170,6 +170,15 @@
(for [item [:layout-max-h :layout-min-h :layout-max-w :layout-min-w]]
[:div.input-element
{:key (d/name item)
;; Execution time translation strings:
;; workspace.options.layout-item.layout-max-h
;; workspace.options.layout-item.layout-max-w
;; workspace.options.layout-item.layout-min-h
;; workspace.options.layout-item.layout-min-w
;; workspace.options.layout-item.title.layout-max-h
;; workspace.options.layout-item.title.layout-max-w
;; workspace.options.layout-item.title.layout-min-h
;; workspace.options.layout-item.title.layout-min-w
:alt (tr (dm/str "workspace.options.layout-item." (d/name item)))
:title (tr (dm/str "workspace.options.layout-item." (d/name item)))
:class (dom/classnames "maxH" (= item :layout-max-h)

View file

@ -49,10 +49,142 @@
(defn translation-keyname
[type keyname]
;; Execution time translation strings:
;; shortcut-subsection.alignment
;; shortcut-subsection.edit
;; shortcut-subsection.general-dashboard
;; shortcut-subsection.general-viewer
;; shortcut-subsection.main-menu
;; shortcut-subsection.modify-layers
;; shortcut-subsection.navigation-dashboard
;; shortcut-subsection.navigation-viewer
;; shortcut-subsection.navigation-workspace
;; shortcut-subsection.panels
;; shortcut-subsection.path-editor
;; shortcut-subsection.shape
;; shortcut-subsection.tools
;; shortcut-subsection.zoom-viewer
;; shortcut-subsection.zoom-workspace
;; shortcuts.add-comment
;; shortcuts.add-node
;; shortcuts.align-bottom
;; shortcuts.align-hcenter
;; shortcuts.align-left
;; shortcuts.align-right
;; shortcuts.align-top
;; shortcuts.align-vcenter
;; shortcuts.artboard-selection
;; shortcuts.bool-difference
;; shortcuts.bool-exclude
;; shortcuts.bool-intersection
;; shortcuts.bool-union
;; shortcuts.bring-back
;; shortcuts.bring-backward
;; shortcuts.bring-forward
;; shortcuts.bring-front
;; shortcuts.clear-undo
;; shortcuts.copy
;; shortcuts.create-component
;; shortcuts.create-new-project
;; shortcuts.cut
;; shortcuts.decrease-zoom
;; shortcuts.delete
;; shortcuts.delete-node
;; shortcuts.detach-component
;; shortcuts.draw-curve
;; shortcuts.draw-ellipse
;; shortcuts.draw-frame
;; shortcuts.draw-nodes
;; shortcuts.draw-path
;; shortcuts.draw-rect
;; shortcuts.draw-text
;; shortcuts.duplicate
;; shortcuts.escape
;; shortcuts.export-shapes
;; shortcuts.fit-all
;; shortcuts.flip-horizontal
;; shortcuts.flip-vertical
;; shortcuts.go-to-drafts
;; shortcuts.go-to-libs
;; shortcuts.go-to-search
;; shortcuts.group
;; shortcuts.h-distribute
;; shortcuts.hide-ui
;; shortcuts.increase-zoom
;; shortcuts.insert-image
;; shortcuts.join-nodes
;; shortcuts.make-corner
;; shortcuts.make-curve
;; shortcuts.mask
;; shortcuts.merge-nodes
;; shortcuts.move
;; shortcuts.move-fast-down
;; shortcuts.move-fast-left
;; shortcuts.move-fast-right
;; shortcuts.move-fast-up
;; shortcuts.move-nodes
;; shortcuts.move-unit-down
;; shortcuts.move-unit-left
;; shortcuts.move-unit-right
;; shortcuts.move-unit-up
;; shortcuts.next-frame
;; shortcuts.opacity-0
;; shortcuts.opacity-1
;; shortcuts.opacity-2
;; shortcuts.opacity-3
;; shortcuts.opacity-4
;; shortcuts.opacity-5
;; shortcuts.opacity-6
;; shortcuts.opacity-7
;; shortcuts.opacity-8
;; shortcuts.opacity-9
;; shortcuts.open-color-picker
;; shortcuts.open-comments
;; shortcuts.open-dashboard
;; shortcuts.open-handoff
;; shortcuts.open-interactions
;; shortcuts.open-viewer
;; shortcuts.open-workspace
;; shortcuts.paste
;; shortcuts.prev-frame
;; shortcuts.redo
;; shortcuts.reset-zoom
;; shortcuts.select-all
;; shortcuts.separate-nodes
;; shortcuts.show-pixel-grid
;; shortcuts.show-shortcuts
;; shortcuts.snap-nodes
;; shortcuts.snap-pixel-grid
;; shortcuts.start-editing
;; shortcuts.start-measure
;; shortcuts.stop-measure
;; shortcuts.thumbnail-set
;; shortcuts.toggle-alignment
;; shortcuts.toggle-assets
;; shortcuts.toggle-colorpalette
;; shortcuts.toggle-focus-mode
;; shortcuts.toggle-grid
;; shortcuts.toggle-history
;; shortcuts.toggle-layers
;; shortcuts.toggle-lock
;; shortcuts.toggle-lock-size
;; shortcuts.toggle-rules
;; shortcuts.toggle-scale-text
;; shortcuts.toggle-snap-grid
;; shortcuts.toggle-snap-guide
;; shortcuts.toggle-textpalette
;; shortcuts.toggle-visibility
;; shortcuts.toggle-zoom-style
;; shortcuts.toogle-fullscreen
;; shortcuts.undo
;; shortcuts.ungroup
;; shortcuts.unmask
;; shortcuts.v-distribute
;; shortcuts.zoom-selected
(let [translat-pre (case type
:sc "shortcuts."
:sec "shortcut-section."
:sub-sec "shortcut-subsection.")]
:sc "shortcuts."
:sec "shortcut-section."
:sub-sec "shortcut-subsection.")]
(tr (str translat-pre (d/name keyname)))))
(defn add-translation