mozilla / testpilot

Test Pilot is a platform for performing controlled tests of new product concepts in Firefox
https://testpilot.firefox.com/
251 stars 123 forks source link

Verify production locales for EOL #4032

Closed pdehaan closed 5 years ago

pdehaan commented 5 years ago

Current production locales:

https://github.com/mozilla/testpilot/blob/13c27266c6c29b77b9290691211f55451fe98ccb/src/index.html#L6-L7

I wrote a pretty sub-standard .ftl parsing bot which scans all the locales/*/app.ftl files for the EOL specific strings and reports back the production locales which are 100% translated (ignoring the old strings):

source ```js const fs = require("fs"); const { parse } = require("fluent-syntax"); const glob = require("glob"); // Required "Term" and "Message" keys from the .ftl file. const requiredKeys = [ // Terms "brand", "product", "exp-containers", "exp-activity-stream", "exp-screenshots", "exp-lockbox", "exp-send", "exp-color", "exp-side-view", "exp-email-tabs", "exp-notes", "exp-price-wise", // Messages "eolTitle", "eolMessageOne", "eolMessageTwo", "eolMessageThree", "eolMessageFour", "eolMessageFive", "eolMessageClose", "eolMessageSignature" ]; glob("./locales/*/app.ftl", (err, files) => { const productionLocales = []; if (err) { console.error(err); return; } for (const file of files) { const ftl = fs.readFileSync(file, "utf-8"); const res = parse(ftl); const keys = new Set(); const missingKeys = []; res.body.forEach(r => { switch (r.type) { case "GroupComment": // Ignore... break; case "Message": case "Term": keys.add(r.id.name); break; default: console.log("Whats this?", r); break; } }); requiredKeys.forEach(key => { if (!keys.has(key)) { missingKeys.push(` Missing required key: ${key}`); } }); if (missingKeys.length === 0) { // Warning, named regex groups. May require Node 10+. const {groups: {locale}} = file.match(new RegExp("^./locales/(?.*)/app.ftl$")); productionLocales.push(locale); } else { // console.log(file); // console.log(missingKeys.join("\n")); } } console.log("Production locales:", productionLocales.sort().join(", ")); }); ```
$ git rev-parse --short HEAD # 13c27266
$ node eol-lint.js

Production locales: cs, cy, de, en-CA, en-US, es-AR, fr, hu, pt-PT, sk, sv-SE, tr, zh-CN, zh-TW
pdehaan commented 5 years ago

TL;DR: Our current production locale config is:

<meta name="availableLanguages" 
  content="en-US, cs, cy, de, en-CA, es-AR, es-MX, fr, hsb, hu, pt-PT, sk, sl, sv-SE, tr, zh-CN, zh-TW"/>

If I specifically check those locales, there are a couple which have a few missing strings:

glob("./locales/*(en-US|cs|cy|de|en-CA|es-AR|es-MX|fr|hsb|hu|pt-PT|sk|sl|sv-SE|tr|zh-CN|zh-TW)/app.ftl", (err, files) => {
./locales/es-MX/app.ftl
  Missing required key: brand
  Missing required key: product
  Missing required key: exp-activity-stream
  Missing required key: exp-side-view
  Missing required key: eolTitle
  Missing required key: eolMessageOne
  Missing required key: eolMessageTwo
  Missing required key: eolMessageThree
  Missing required key: eolMessageFour
  Missing required key: eolMessageFive
  Missing required key: eolMessageClose

./locales/hsb/app.ftl
  Missing required key: eolMessageTwo
  Missing required key: eolMessageThree
  Missing required key: eolMessageFive

./locales/sl/app.ftl
  Missing required key: eolTitle
  Missing required key: eolMessageTwo
  Missing required key: eolMessageThree
  Missing required key: eolMessageFour
  Missing required key: eolMessageFive
  Missing required key: eolMessageClose

Production locales: cs, cy, de, en-CA, en-US, es-AR, fr, hu, pt-PT, sk, sv-SE, tr, zh-CN, zh-TW
pdehaan commented 5 years ago

Using the latest strings from $ git rev-parse --short HEAD # e705308c, I think we're missing es-CL,ka,sq from our current list of locales:

https://github.com/mozilla/testpilot/blob/e705308cdd09dbd211a12ecf55542f3c95cf34c4/src/index.html#L6-L7

Prod ready locales:  cs,cy,de,dsb,el,en-CA,en-US,es-AR,es-CL,es-ES,fr,fy-NL,hsb,hu,it,ka,nl,pt-PT,ru,sk,sl,sq,sv-SE,tr,zh-CN,zh-TW
Current locales:     cs,cy,de,dsb,el,en-CA,en-US,es-AR,es-ES,fr,fy-NL,hsb,hu,it,nl,pt-PT,ru,sk,sl,sv-SE,tr,zh-CN,zh-TW
Missing locales:     es-CL,ka,sq
source ```js // npm i cheerio fluent-syntax glob -S const fs = require("fs"); const cheerio = require("cheerio"); const { parse } = require("fluent-syntax"); const glob = require("glob"); // Required "Term" and "Message" keys from the .ftl file. const requiredKeys = [ // Terms "brand", "product", "exp-containers", "exp-activity-stream", "exp-screenshots", "exp-lockbox", "exp-send", "exp-color", "exp-side-view", "exp-email-tabs", "exp-notes", "exp-price-wise", // Messages "eolTitle", "eolMessageOne", "eolMessageTwo", "eolMessageThree", "eolMessageFour", "eolMessageFive", "eolMessageClose", "eolMessageSignature" ]; // "./locales/*(en-US|cs|cy|de|en-CA|es-AR|es-MX|fr|hsb|hu|pt-PT|sk|sl|sv-SE|tr|zh-CN|zh-TW)/app.ftl" glob("./locales/*/app.ftl", (err, files) => { const productionLocales = []; if (err) { console.error(err); return; } for (const file of files) { const ftl = fs.readFileSync(file, "utf-8"); const { body } = parse(ftl); const keys = new Set(); const missingKeys = []; body.forEach(r => { switch (r.type) { case "GroupComment": // Ignore... break; case "Message": case "Term": keys.add(r.id.name); break; default: console.log("Whats this?", r); break; } }); requiredKeys.forEach(key => { if (!keys.has(key)) { missingKeys.push(` Missing required key: ${key}`); } }); if (missingKeys.length === 0) { // Warning, named regex groups. May require Node 10+. const { groups: { locale } } = file.match(new RegExp("^./locales/(?.*)/app.ftl$")); productionLocales.push(locale); } else { console.log(file); console.log(missingKeys.join("\n")); } } const currentLocales = getCurrentLocales("./src/index.html"); const missingLocales = getMissingLocales(productionLocales, currentLocales); console.log("\n"); console.log("Prod ready locales:\t", productionLocales.sort().join(",")); console.log("Current locales:\t", currentLocales.join(",")); console.log("Missing locales:\t", missingLocales.join(",")); }); function getCurrentLocales(template) { const html = fs.readFileSync(template, "utf-8"); const $ = cheerio.load(html); return $("meta[name='availableLanguages']") .attr("content") .split(",") .map(lang => lang.trim()) .sort(); } function getMissingLocales(production, current) { return production .filter(locale => !current.includes(locale)) .sort(); } ```