diff --git a/README.md b/README.md index 7ca96434c..d442dca59 100644 --- a/README.md +++ b/README.md @@ -214,3 +214,10 @@ The following list of features is not complete, but gives you a rough idea of wh - Serverless Fontra - Peer-to-peer collaboration + +## Translations + +We are maintaining various language translations of the UI in a spreadsheet. Please contact us if you'd like to contribute (to) a translation. + +- [Translation Documentation](https://docs.google.com/spreadsheets/d/1woTU8dZCHJh7yvdk-N1kgQBUj4Sn3SdRsbKgn6ltJQs/edit?gid=1731105247#gid=1731105247) +- [Fontra UI Strings spreadsheet](https://docs.google.com/spreadsheets/d/1woTU8dZCHJh7yvdk-N1kgQBUj4Sn3SdRsbKgn6ltJQs/edit?usp=sharing) diff --git a/scripts/rebuild_languages.py b/scripts/rebuild_languages.py new file mode 100644 index 000000000..e52bc52e9 --- /dev/null +++ b/scripts/rebuild_languages.py @@ -0,0 +1,131 @@ +import csv +import io +import json +import os +import pathlib +import subprocess +from urllib.request import urlopen + + +def prettier(path): + subprocess.run( + [ + os.fspath(repoDir / "node_modules" / ".bin" / "prettier"), + os.fspath(path), + "--write", + ], + check=True, + ) + + +def jsonDump(s): + return json.dumps(s, ensure_ascii=False) + + +def downloadSheet(url): + print("downloading", url) + response = urlopen(url) + data = response.read() + file = io.StringIO(data.decode("utf-8")) + reader = csv.reader(file) + return list(reader) + + +languageSpreadsheetURL = ( + "https://docs.google.com/" + "spreadsheets/d/1woTU8dZCHJh7yvdk-N1kgQBUj4Sn3SdRsbKgn6ltJQs/" + "export?format=csv&gid=1383907145" +) + +rows = downloadSheet(languageSpreadsheetURL) + +numHeaders = 5 +headers = rows[:numHeaders] +assert headers[0][0] == "Documentation", headers[0][0] +assert headers[1][2] == "English", headers[1][2] +assert headers[2][2] == "English", headers[2][2] +assert headers[3][2] == "en", headers[3][2] + +rows = rows[numHeaders:] + +startColumn = 2 + +languages = [] +languageStrings = {} + +for columnIndex in range(startColumn, len(headers[1])): + languageInEnglish = headers[1][columnIndex] + languageInLanguage = headers[2][columnIndex] + languageCode = headers[3][columnIndex] + languageStatus = headers[4][columnIndex] + assert languageCode + if not languageStatus.strip(): + continue + + languages.append( + dict( + code=languageCode, + langEn=languageInEnglish, + langLang=languageInLanguage, + status=languageStatus, + ) + ) + + languageStrings[languageCode] = strings = {} + + for row in rows: + key = row[1] + if not key.strip(): + continue + string = row[columnIndex] + if not string or string == "-": + string = languageStrings["en"].get(key, "!missing!") + strings[key] = string + + +repoDir = pathlib.Path(__file__).resolve().parent.parent +langDir = repoDir / "src" / "fontra" / "client" / "lang" +assert langDir.is_dir() +localizationJSPath = repoDir / "src" / "fontra" / "client" / "core" / "localization.js" +assert localizationJSPath.is_file() + +localizationJSSource = localizationJSPath.read_text(encoding="utf-8") + +languagesList = "\n".join(f" {jsonDump(langs)}," for langs in languages) +languagesBlock = f"""// Don't edit this block, see scripts/rebuild_languages.py +export const languages = [ +{languagesList} +]; +""" + +indexStart = localizationJSSource.find(languagesBlock.splitlines()[0]) +assert indexStart > 0 +indexEnd = localizationJSSource.find("];\n", indexStart) +assert indexEnd > indexStart + +localizationJSSource = ( + localizationJSSource[:indexStart] + + languagesBlock + + localizationJSSource[indexEnd + 3 :] +) + +localizationJSPath.write_text(localizationJSSource, encoding="utf-8") +prettier(localizationJSPath) + + +languageSourceTemplate = """// Don't edit this file: it is generated by scripts/rebuild_languages.py +export const strings = {{ +{stringsBlock} +}}; +""" + +for languageCode, strings in languageStrings.items(): + languagePath = langDir / f"{languageCode.strip()}.js" + print("writing", languagePath) + lines = [] + for k, v in sorted(strings.items()): + lines.append(f" {jsonDump(k.strip())}: {jsonDump(v)},") + stringsBlock = "\n".join(lines) + languageSource = languageSourceTemplate.format(stringsBlock=stringsBlock) + languagePath.write_text(languageSource, encoding="utf-8") + prettier(languagePath) diff --git a/src/fontra/client/core/localization.js b/src/fontra/client/core/localization.js index ae18b6221..1c245dcaf 100644 --- a/src/fontra/client/core/localization.js +++ b/src/fontra/client/core/localization.js @@ -1,5 +1,11 @@ import { ObservableController } from "./observable-object.js"; -import { fetchJSON } from "./utils.js"; + +// Don't edit this block, see scripts/rebuild_languages.py +export const languages = [ + { code: "en", langEn: "English", langLang: "English", status: "done" }, + { code: "zh-CN", langEn: "Simplified Chinese", langLang: "简体中文", status: "beta" }, + { code: "nl", langEn: "Dutch", langLang: "Nederlands", status: "wip" }, +]; const debugTranslation = false; let localizationData = {}; @@ -20,9 +26,9 @@ export const ensureLanguageHasLoaded = new Promise((resolve) => { function languageChanged(locale) { // Do explicit .replace() because our cache busting mechanism is simplistic, // and backtick strings don't work. - const translationsPath = "/lang/locale.json".replace("locale", locale); - fetchJSON(translationsPath).then((data) => { - localizationData = data; + const translationsPath = "/lang/locale.js".replace("locale", locale); + import(translationsPath).then((mod) => { + localizationData = mod.strings; resolveLanguageHasLoaded(); }); } diff --git a/src/fontra/client/lang/en.json b/src/fontra/client/lang/en.js similarity index 95% rename from src/fontra/client/lang/en.json rename to src/fontra/client/lang/en.js index 4c96e8524..f64002d38 100644 --- a/src/fontra/client/lang/en.json +++ b/src/fontra/client/lang/en.js @@ -1,4 +1,5 @@ -{ +// Don't edit this file: it is generated by scripts/rebuild_languages.py +export const strings = { "action-topics.designspace-navigation": "Designspace Navigation", "action-topics.export-as": "Export as", "action-topics.glyph-editor-appearance": "Glyph editor appearance", @@ -36,6 +37,8 @@ "action.set-contour-start": "Set Start Point", "action.undo": "Undo", "application-settings.clipboard.title": "Clipboard", + "application-settings.display-language.status.beta": "beta", + "application-settings.display-language.status.wip": "work in progress", "application-settings.display-language.title": "Display Language", "application-settings.editor-behavior.title": "Editor Behavior", "application-settings.plugins-manager.title": "Plugin Manager", @@ -81,9 +84,10 @@ "dialog.add": "Add", "dialog.cancel": "Cancel", "dialog.create": "Create", - "dialog.create-new-glyph.body": "Click \"Create\" if you want to create a new glyph named \"%0\"%1.", - "dialog.create-new-glyph.body.2": " for character \"%0\" (%1)", - "dialog.create-new-glyph.title": "Create a new glyph \"%0\"?", + "dialog.create-new-glyph.body": + 'Click "Create" if you want to create a new glyph named "%0"%1.', + "dialog.create-new-glyph.body.2": ' for character "%0" (%1)', + "dialog.create-new-glyph.title": 'Create a new glyph "%0"?', "dialog.glyphs.search": "Search glyphs", "dialog.replace": "Replace", "editor.hand-tool": "Hand Tool", @@ -155,7 +159,8 @@ "sidebar.reference-font": "Reference Font", "sidebar.referencefont": "Reference font", "sidebar.referencefont.customcharacter": "Custom character", - "sidebar.referencefont.info": "Drop one or more .ttf, .otf, .woff or .woff2 files in the field below", + "sidebar.referencefont.info": + "Drop one or more .ttf, .otf, .woff or .woff2 files in the field below", "sidebar.referencefont.language": "Language", "sidebar.related-glyphs": "Related Glyphs & Characters", "sidebar.related-glyphs.title": "Related Glyphs & Characters for %0", @@ -239,5 +244,5 @@ "toggle-fullscreen": "Toggle Fullscreen", "zoom-fit-selection": "Zoom To Fit Selection", "zoom-in": "Zoom In", - "zoom-out": "Zoom Out" -} + "zoom-out": "Zoom Out", +}; diff --git a/src/fontra/client/lang/nl.js b/src/fontra/client/lang/nl.js new file mode 100644 index 000000000..0900c19e9 --- /dev/null +++ b/src/fontra/client/lang/nl.js @@ -0,0 +1,249 @@ +// Don't edit this file: it is generated by scripts/rebuild_languages.py +export const strings = { + "action-topics.designspace-navigation": "Designspace Navigatie", + "action-topics.export-as": "Exporteer als", + "action-topics.glyph-editor-appearance": "Glyph editor uiterlijk", + "action-topics.menu.edit": "Wijzig", + "action-topics.menu.view": "Weergave", + "action-topics.selection-transformations": "Selection Transformations", + "action-topics.sidebars": "Zijbalken", + "action-topics.tools": "Gereedschappen", + "action.add-anchor": "Voeg anker toe", + "action.add-component": "Voeg component toe", + "action.add-guideline": "Voeg hulplijn toe", + "action.break-contour": "Breek contour", + "action.close-contour": "Sluit %0 contour", + "action.close-contour.plural": "Sluit %0 contouren", + "action.copy": "Kopiëer", + "action.cut": "Snij", + "action.decompose-component": "Decompose %0 Component", + "action.decompose-component.plural": "Decompose %0 Components", + "action.delete": "Verwijder", + "action.delete-glyph": "Verwijder glyph", + "action.delete-selection": "Verwijder selectie", + "action.export-as.designspace": "Designspace + UFO (*.designspace)", + "action.export-as.fontra": "Fontra (*.fontra)", + "action.export-as.otf": "OpenType (*.otf)", + "action.export-as.rcjk": "RCJK (*.rcjk)", + "action.export-as.ttf": "TrueType (*.ttf)", + "action.export-as.ufo": "UFO (*.ufo)", + "action.join-contours": "Verbind contouren", + "action.lock-guidelines": "Vergrendel hulplijnen", + "action.paste": "Plak", + "action.redo": "Opnieuw", + "action.reverse-contour": "Keer contour richting om", + "action.select-all": "Selecteer alles", + "action.select-none": "Selecteer niets", + "action.set-contour-start": "Maak startpunt", + "action.undo": "Herstel", + "application-settings.clipboard.title": "Klembord", + "application-settings.display-language.status.beta": "beta", + "application-settings.display-language.status.wip": "in ontwikkeling", + "application-settings.display-language.title": "Weergavetaal", + "application-settings.editor-behavior.title": "Editor gedrag", + "application-settings.plugins-manager.title": "Plugin Manager", + "application-settings.server-info.title": "Server info", + "application-settings.shortcuts.title": "Snelkoppelingen", + "application-settings.theme-settings.title": "Thema instellingen", + "axes.add": "Voeg nieuwe as toe", + "axes.axis-values": "As waarden", + "axes.create": "Nieuwe as", + "axes.delete-axis": "Verwijder as", + "axes.mapping-graph": "Mapping grafiek", + "axes.mapping-list": "Mapping lijst", + "axes.mapping.source": "Source", + "axes.mapping.user": "User", + "axes.mapping.values.elidable": "Elidable", + "axes.mapping.values.linked": "Linked", + "axes.mapping.values.max": "Max", + "axes.mapping.values.min": "Min", + "axes.mapping.values.name": "Naam", + "axes.mapping.values.value": "Waarde", + "axes.names": "Namen", + "axes.names.name": "Naam", + "axes.names.ot-tag": "OT tag", + "axes.names.ui-name": "UI name", + "axes.new": "Niewe as...", + "axes.preset": "Standaard assen", + "axes.preset.italic": "Cursief", + "axes.preset.optical-size": "Optische grootte", + "axes.preset.slant": "Hellingshoek", + "axes.preset.weight": "Gewicht", + "axes.preset.width": "Breedte", + "axes.range": "Bereik", + "axes.range.axis-type": "As type", + "axes.range.axis-type.continuous": "Doorlopend", + "axes.range.axis-type.discrete": "Discreet", + "axes.range.default": "Standaard", + "axes.range.maxium": "Maximum", + "axes.range.minumum": "Minimum", + "axes.range.values": "Waarden", + "axes.title": "Assen", + "canvas.clean-view-and-hand-tool": "Schone weergave en Hand gereedschap", + "designspace-navigation.edit-all-compatible-sources": + "Wijzig alle compatibele sources", + "dialog.add": "Voeg toe", + "dialog.cancel": "Annuleren", + "dialog.create": "Maak", + "dialog.create-new-glyph.body": + 'Click "Create" if you want to create a new glyph named "%0"%1.', + "dialog.create-new-glyph.body.2": ' for character "%0" (%1)', + "dialog.create-new-glyph.title": 'Create a new glyph "%0"?', + "dialog.glyphs.search": "Search glyphs", + "dialog.replace": "Replace", + "editor.hand-tool": "Hand Tool", + "editor.knife-tool": "Knife Tool", + "editor.pen-tool": "Pen Tool", + "editor.pen-tool-cubic": "Pen Tool (cubic)", + "editor.pen-tool-quad": "Pen Tool (quadratic)", + "editor.pointer-tool": "Pointer Tool", + "editor.pointer-tool-scale": "Pointer Tool (Scaling edit tool behavior)", + "editor.power-ruler-tool": "Power Ruler Tool", + "editor.shape-tool": "Shape Tool", + "editor.shape-tool-ellipse": "Shape Tool Ellipse", + "editor.shape-tool-rectangle": "Shape Tool Rectangle", + "font-info.copyright": "Copyright", + "font-info.description": "Description", + "font-info.designer": "Designer", + "font-info.designer.url": "Designer URL", + "font-info.familyname": "Family name", + "font-info.licensedescription": "License description", + "font-info.licenseinfo.url": "License info URL", + "font-info.manufacturer": "Manufacturer", + "font-info.sampletext": "Sample text", + "font-info.title": "Font Info", + "font-info.trademark": "Trademark", + "font-info.vendorid": "Vendor ID", + "font-info.version.major": "Version Major", + "font-info.version.minor": "Version Minor", + "font-infomanufacturer.url": "Manufacturer URL", + "language.en": "English", + "language.zh-cn": "Simplified Chinese", + "menubar.edit": "Edit", + "menubar.extensions": "Extensions", + "menubar.file": "File", + "menubar.file.export-as": "Export as", + "menubar.file.new": "New...", + "menubar.file.open": "Open...", + "menubar.font": "Font", + "menubar.font.edit": "Edit Font Info, Axes and Sources", + "menubar.fontra.application-settings": "Application Settings", + "menubar.glyph": "Glyph", + "menubar.glyph.add": "Add source...", + "menubar.glyph.delete": "Delete source...", + "menubar.glyph.edit-axes": "Edit glyph axes...", + "menubar.help": "Help", + "menubar.help.documentation": "Documentation", + "menubar.help.homepage": "Homepage", + "menubar.view": "View", + "menubar.view.add-glyph-after-selected-glyph": "Add glyph after selected glyph", + "menubar.view.add-glyph-before-selected-glyph": "Add glyph before selected glyph", + "menubar.view.find-glyphs-that-use": "Find glyphs that use '%0'", + "menubar.view.remove-selected-glyph-from-canvas": "Remove selected glyph from canvas", + "menubar.view.replace-selected-glyph-on-canvas": "Replace selected glyph on canvas", + "menubar.view.select-next-source": "Select next source", + "menubar.view.select-previous-source": "Select previous source", + "selection.none": "(No selection)", + "sidebar.designspace-navigation": "Designspace Navigation", + "sidebar.designspace-navigation.font-axes": "Font axes", + "sidebar.designspace-navigation.font-axes.edit": "Edit font axes", + "sidebar.designspace-navigation.font-axes.reset": "Reset font axes", + "sidebar.designspace-navigation.glyph-axes": "Glyph axes", + "sidebar.designspace-navigation.glyph-axes.edit": "Edit glyph axes", + "sidebar.designspace-navigation.glyph-axes.reset": "Reset glyph axes", + "sidebar.designspace-navigation.glyph-sources": "Glyph sources", + "sidebar.designspace-navigation.glyph-sources.name": "source name", + "sidebar.designspace-navigation.glyph-sources.status": "status", + "sidebar.glyph-note": "Glyph Note", + "sidebar.glyph-search": "Glyph Search", + "sidebar.glyphs.search": "Search glyphs", + "sidebar.reference-font": "Reference Font", + "sidebar.referencefont": "Reference font", + "sidebar.referencefont.customcharacter": "Custom character", + "sidebar.referencefont.info": + "Drop one or more .ttf, .otf, .woff or .woff2 files in the field below", + "sidebar.referencefont.language": "Language", + "sidebar.related-glyphs": "Related Glyphs & Characters", + "sidebar.related-glyphs.title": "Related Glyphs & Characters for %0", + "sidebar.selection-info": "Selection Info", + "sidebar.selection-info.advance-width": "Advance width", + "sidebar.selection-info.component": "Component #%0", + "sidebar.selection-info.component.base-glyph": "Base glyph", + "sidebar.selection-info.component.center": "Center", + "sidebar.selection-info.component.rotation": "Rotation", + "sidebar.selection-info.component.scale": "Scale", + "sidebar.selection-info.component.skew": "Skew", + "sidebar.selection-info.component.transformation": "Transformation", + "sidebar.selection-info.component.translate": "Translate", + "sidebar.selection-info.dimensions": "Dimensions", + "sidebar.selection-info.glyph-name": "Glyph name", + "sidebar.selection-info.multi-source": "Multi-source value changes are absolute", + "sidebar.selection-info.sidebearings": "Sidebearings", + "sidebar.selection-info.title": "Glyph info", + "sidebar.selection-transformation": "Selection Transformation", + "sidebar.selection-transformation.align": "Align Objects", + "sidebar.selection-transformation.align.bottom": "Align bottom", + "sidebar.selection-transformation.align.center": "Align center", + "sidebar.selection-transformation.align.left": "Align left", + "sidebar.selection-transformation.align.middle": "Align middle", + "sidebar.selection-transformation.align.right": "Align right", + "sidebar.selection-transformation.align.top": "Align top", + "sidebar.selection-transformation.distribute": "Distribute Objects", + "sidebar.selection-transformation.distribute.horizontally": "Distribute horizontally", + "sidebar.selection-transformation.distribute.vertically": "Distribute vertically", + "sidebar.selection-transformation.flip": "Flip", + "sidebar.selection-transformation.flip.horizontally": "Flip Horizontally", + "sidebar.selection-transformation.flip.vertically": "Flip Vertically", + "sidebar.selection-transformation.move": "Move", + "sidebar.selection-transformation.origin": "Origin", + "sidebar.selection-transformation.origin.bottom.center": "Origin bottom center", + "sidebar.selection-transformation.origin.bottom.left": "Origin bottom left", + "sidebar.selection-transformation.origin.bottom.right": "Origin bottom right", + "sidebar.selection-transformation.origin.middle.center": "Origin middle center", + "sidebar.selection-transformation.origin.middle.left": "Origin middle left", + "sidebar.selection-transformation.origin.middle.right": "Origin middle right", + "sidebar.selection-transformation.origin.top.center": "Origin top center", + "sidebar.selection-transformation.origin.top.left": "Origin top left", + "sidebar.selection-transformation.origin.top.right": "Origin top right", + "sidebar.selection-transformation.path-operations": "Path Operations", + "sidebar.selection-transformation.path-operations.exclude": "Exclude contours", + "sidebar.selection-transformation.path-operations.intersect": "Intersect contours", + "sidebar.selection-transformation.path-operations.subtract": "Subtract contours", + "sidebar.selection-transformation.path-operations.union": "Remove overlaps", + "sidebar.selection-transformation.rotate": "Rotate", + "sidebar.selection-transformation.scale": "Scale", + "sidebar.selection-transformation.skew": "Skew", + "sidebar.selection-transformation.title": "Transformation", + "sidebar.text-entry": "Text Entry", + "sidebar.user-settings": "User Settings", + "sidebar.user-settings.clipboard": "Clipboard export format", + "sidebar.user-settings.component.nodes": "Component nodes and handles", + "sidebar.user-settings.experimental": "Experimental features", + "sidebar.user-settings.glyph": "Glyph editor appearance", + "sidebar.user-settings.glyph.anchornames": "Anchor names", + "sidebar.user-settings.glyph.baseline": "Baseline", + "sidebar.user-settings.glyph.cjkframe": "CJK Design Frame", + "sidebar.user-settings.glyph.component": "Component names and indices", + "sidebar.user-settings.glyph.contour": "Contour indices", + "sidebar.user-settings.glyph.coordinates": "Coordinates", + "sidebar.user-settings.glyph.dragcrosshair": "Drag crosshair", + "sidebar.user-settings.glyph.dragghostpath": "Drag “ghost” path", + "sidebar.user-settings.glyph.lockicon": "Glyph lock icon for non-editing glyphs", + "sidebar.user-settings.glyph.point.index": "Point indices", + "sidebar.user-settings.glyph.powerruler": "Power Ruler", + "sidebar.user-settings.glyph.referencefont": "Reference font", + "sidebar.user-settings.glyph.sidebearings": "Sidebearings for non-editing glyphs", + "sidebar.user-settings.glyph.statuscolor": "Development status color", + "sidebar.user-settings.glyph.upmgrid": "Units-per-em grid", + "sidebar.user-settings.language": "Display language", + "sidebar.user-settings.server": "Server info", + "sidebar.user-settings.theme": "Theme settings", + "sidebar.user-settings.theme.auto": "Automatic (use OS setting)", + "sidebar.user-settings.theme.dark": "Dark", + "sidebar.user-settings.theme.light": "Light", + "sources.title": "Sources", + "toggle-fullscreen": "Toggle Fullscreen", + "zoom-fit-selection": "Zoom To Fit Selection", + "zoom-in": "Zoom In", + "zoom-out": "Zoom Out", +}; diff --git a/src/fontra/client/lang/zh-CN.json b/src/fontra/client/lang/zh-CN.js similarity index 94% rename from src/fontra/client/lang/zh-CN.json rename to src/fontra/client/lang/zh-CN.js index 8ef1d4e4f..2524edeea 100644 --- a/src/fontra/client/lang/zh-CN.json +++ b/src/fontra/client/lang/zh-CN.js @@ -1,4 +1,5 @@ -{ +// Don't edit this file: it is generated by scripts/rebuild_languages.py +export const strings = { "action-topics.designspace-navigation": "Designspace 导航", "action-topics.export-as": "Export as", "action-topics.glyph-editor-appearance": "字符形编辑器外观", @@ -16,6 +17,7 @@ "action.copy": "Copy", "action.cut": "Cut", "action.decompose-component": "释放 %0 个组件", + "action.decompose-component.plural": "Decompose %0 Components", "action.delete": "Delete", "action.delete-glyph": "删除字符形", "action.delete-selection": "删除选中", @@ -35,6 +37,8 @@ "action.set-contour-start": "设置起点", "action.undo": "撤销", "application-settings.clipboard.title": "剪贴板导出格式", + "application-settings.display-language.status.beta": "beta", + "application-settings.display-language.status.wip": "work in progress", "application-settings.display-language.title": "Display Language", "application-settings.editor-behavior.title": "Editor Behavior", "application-settings.plugins-manager.title": "插件管理器", @@ -80,9 +84,9 @@ "dialog.add": "Add", "dialog.cancel": "取消", "dialog.create": "创建", - "dialog.create-new-glyph.body": "如果你想%1创建一个新的字符形\"%0\",请点击 \"创建\"。", - "dialog.create-new-glyph.body.2": "为字符\"%0\" (%1)", - "dialog.create-new-glyph.title": "创建新字符形 \"%0\"?", + "dialog.create-new-glyph.body": '如果你想%1创建一个新的字符形"%0",请点击 "创建"。', + "dialog.create-new-glyph.body.2": '为字符"%0" (%1)', + "dialog.create-new-glyph.title": '创建新字符形 "%0"?', "dialog.glyphs.search": "搜索字符形", "dialog.replace": "Replace", "editor.hand-tool": "拖拽工具", @@ -111,7 +115,6 @@ "font-info.version.major": "主要版本号", "font-info.version.minor": "次要版本号", "font-infomanufacturer.url": "生产商网址", - "fontinfo.familyname": "字体家族名称", "language.en": "英语", "language.zh-cn": "简体中文", "menubar.edit": "编辑", @@ -155,7 +158,8 @@ "sidebar.reference-font": "参考字体", "sidebar.referencefont": "参考字体", "sidebar.referencefont.customcharacter": "自定义字符", - "sidebar.referencefont.info": "将一个或多个.ttf、.otf、.woff或.woff2字体文件拖放到下面的方框内", + "sidebar.referencefont.info": + "将一个或多个.ttf、.otf、.woff或.woff2字体文件拖放到下面的方框内", "sidebar.referencefont.language": "语言", "sidebar.related-glyphs": "Related Glyphs & Characters", "sidebar.related-glyphs.title": "Related Glyphs & Characters for %0", @@ -239,5 +243,5 @@ "toggle-fullscreen": "切换全屏", "zoom-fit-selection": "缩放到选区", "zoom-in": "放大", - "zoom-out": "缩小" -} + "zoom-out": "缩小", +}; diff --git a/src/fontra/views/applicationsettings/panel-display-language.js b/src/fontra/views/applicationsettings/panel-display-language.js index 26e031e2b..f791e1a16 100644 --- a/src/fontra/views/applicationsettings/panel-display-language.js +++ b/src/fontra/views/applicationsettings/panel-display-language.js @@ -1,6 +1,6 @@ import * as html from "../core/html-utils.js"; import { addStyleSheet } from "../core/html-utils.js"; -import { languageController } from "../core/localization.js"; +import { languageController, languages, translate } from "../core/localization.js"; import { BaseInfoPanel } from "./panel-base.js"; addStyleSheet(` @@ -29,6 +29,19 @@ export class DisplayLanguagePanel extends BaseInfoPanel { } cards() { + const languageOptions = languages.map((lang) => { + let displayName = `${lang.langLang} / ${lang.langEn}`; + if (lang.status != "done") { + const statusString = translate( + `application-settings.display-language.status.${lang.status}` + ); + displayName += ` (${statusString})`; + } + return { + key: lang.code, + displayName: displayName, + }; + }); return [ { displayName: "Display Language", @@ -37,10 +50,7 @@ export class DisplayLanguagePanel extends BaseInfoPanel { { key: "language", ui: "radio", - options: [ - { key: "en", displayName: "English" }, - { key: "zh-CN", displayName: "Simplified Chinese" }, - ], + options: languageOptions, }, ], },