buninu-browser 0.2.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/LICENSES/jsmdcui.txt +22 -0
  2. package/README.md +102 -2
  3. package/frontends/wayland/LICENSE-land +21 -0
  4. package/frontends/wayland/README.md +123 -0
  5. package/frontends/wayland/casty/LICENSE +21 -0
  6. package/frontends/wayland/casty/bookmarks.js +32 -0
  7. package/frontends/wayland/casty/click.js +96 -0
  8. package/frontends/wayland/casty/commands.js +61 -0
  9. package/frontends/wayland/casty/config.js +45 -0
  10. package/frontends/wayland/casty/download-directory.js +28 -0
  11. package/frontends/wayland/casty/download.js +49 -0
  12. package/frontends/wayland/casty/hints.js +334 -0
  13. package/frontends/wayland/casty/keys.js +56 -0
  14. package/frontends/wayland/casty/page-commands.js +80 -0
  15. package/frontends/wayland/casty/prompt-width.js +148 -0
  16. package/frontends/wayland/casty/urlbar.js +606 -0
  17. package/frontends/wayland/client.js +88 -0
  18. package/frontends/wayland/clipboard.js +80 -0
  19. package/frontends/wayland/index.js +116 -0
  20. package/frontends/wayland/input.js +56 -0
  21. package/frontends/wayland/protocol.js +55 -0
  22. package/frontends/wayland/protocols/wayland.xml +3248 -0
  23. package/frontends/wayland/protocols/xdg-shell.xml +1415 -0
  24. package/frontends/wayland/transport.js +120 -0
  25. package/frontends/wayland/urlbar.js +158 -0
  26. package/index.js +28 -1
  27. package/lib/clipboard-command.js +10 -0
  28. package/lib/clipboard-powershell.js +22 -0
  29. package/lib/clipboard.js +57 -0
  30. package/lib/document-types.js +11 -0
  31. package/lib/headless-shell.js +78 -13
  32. package/lib/layout/text-layout.js +17 -9
  33. package/lib/paint/display-list.js +5 -1
  34. package/lib/paint/frame.js +35 -3
  35. package/lib/paint/raw-frames.js +47 -0
  36. package/lib/qml/README.md +971 -0
  37. package/lib/qml/builtins.js +700 -0
  38. package/lib/qml/canvas-dom.js +115 -0
  39. package/lib/qml/document.js +1176 -0
  40. package/lib/qml/format.js +9 -0
  41. package/lib/qml/host.js +324 -0
  42. package/lib/qml/images.js +199 -0
  43. package/lib/qml/launcher.js +132 -0
  44. package/lib/qml/loader.js +517 -0
  45. package/lib/qml/media-renderer.js +49 -0
  46. package/lib/qml/media.js +86 -0
  47. package/lib/qml/models.js +622 -0
  48. package/lib/qml/parser.js +381 -0
  49. package/lib/qml/qs +5 -0
  50. package/lib/qml/qscasty +3 -0
  51. package/lib/qml/qsheadless +3 -0
  52. package/lib/qml/qswayland +3 -0
  53. package/lib/qml/reactive.js +159 -0
  54. package/lib/qml/runtime.js +3381 -0
  55. package/lib/qml/shapes.js +243 -0
  56. package/lib/qml/text.js +109 -0
  57. package/lib/qml/textures.js +123 -0
  58. package/lib/qml/wayland-clipboard.js +32 -0
  59. package/lib/qml/worker-thread.js +70 -0
  60. package/lib/render-tree/index.js +16 -1
  61. package/lib/renderer/bindings.js +11 -0
  62. package/lib/renderer/canvas-2d.js +13 -0
  63. package/lib/renderer/compositor-channel.js +103 -0
  64. package/lib/renderer/compositor.js +25 -33
  65. package/lib/renderer/flags.js +1 -1
  66. package/lib/renderer/host.js +128 -92
  67. package/lib/renderer/main.js +38 -4
  68. package/lib/renderer/page-realm.js +32 -1
  69. package/lib/renderer/page-renderer.js +250 -21
  70. package/lib/renderer/text-input-paint.js +54 -0
  71. package/lib/renderer/text-input.js +57 -0
  72. package/lib/style/computed-style.js +2 -2
  73. package/package.json +1 -1
  74. package/test/clipboard.test.js +54 -0
  75. package/test/fixtures/browser-raw-demo.html +36 -0
  76. package/test/fixtures/flea-helpers/Dockerfile +36 -0
  77. package/test/fixtures/flea-helpers/bat.mjs +43 -0
  78. package/test/fixtures/flea-helpers/bin/bat +3 -0
  79. package/test/fixtures/flea-helpers/bin/bwrap +10 -0
  80. package/test/fixtures/flea-helpers/bin/bwrap-real-filter +9 -0
  81. package/test/fixtures/flea-helpers/bin/glow +3 -0
  82. package/test/fixtures/flea-helpers/bin/qs +3 -0
  83. package/test/fixtures/flea-helpers/bin/unsupported +3 -0
  84. package/test/fixtures/flea-helpers/check-highlighting.mjs +47 -0
  85. package/test/fixtures/flea-helpers/check-media.mjs +29 -0
  86. package/test/fixtures/flea-helpers/check-preview.mjs +27 -0
  87. package/test/fixtures/flea-helpers/check.mjs +36 -0
  88. package/test/fixtures/flea-helpers/highlight-cases.json +227 -0
  89. package/test/fixtures/flea-helpers/source-mime.xml +28 -0
  90. package/test/fixtures/flea-helpers/syntax-compat.mjs +23 -0
  91. package/test/fixtures/flea-thumbnail-stub/flea-placeholder.thumbnailer +4 -0
  92. package/test/fixtures/flea-thumbnail-stub/flea-thumbnail-stub +3 -0
  93. package/test/fixtures/qml/flea/EscapeHint.qml +11 -0
  94. package/test/fixtures/qml/flea/LICENSE +21 -0
  95. package/test/fixtures/qml/flea/README.md +25 -0
  96. package/test/fixtures/qml/flea/Theme.qml +8 -0
  97. package/test/fixtures/qml/flea/demo.qml +24 -0
  98. package/test/fixtures/qml/flea/qmldir +3 -0
  99. package/test/fixtures/qml/flea-theme/LICENSE-Flea +21 -0
  100. package/test/fixtures/qml/flea-theme/LICENSE-Omarchy +20 -0
  101. package/test/fixtures/qml/flea-theme/README.md +70 -0
  102. package/test/fixtures/qml/flea-theme/button.qml +17 -0
  103. package/test/fixtures/qml/flea-theme/demo.qml +27 -0
  104. package/test/fixtures/qml/flea-theme/field.qml +21 -0
  105. package/test/fixtures/qml/flea-theme/imports/qs/Commons/BorderGeometry.js +373 -0
  106. package/test/fixtures/qml/flea-theme/imports/qs/Commons/Color.qml +258 -0
  107. package/test/fixtures/qml/flea-theme/imports/qs/Commons/I18n.qml +118 -0
  108. package/test/fixtures/qml/flea-theme/imports/qs/Commons/Numbers.js +19 -0
  109. package/test/fixtures/qml/flea-theme/imports/qs/Commons/Plural.js +91 -0
  110. package/test/fixtures/qml/flea-theme/imports/qs/Commons/Style.qml +561 -0
  111. package/test/fixtures/qml/flea-theme/imports/qs/Commons/Util.qml +188 -0
  112. package/test/fixtures/qml/flea-theme/imports/qs/Commons/qmldir +13 -0
  113. package/test/fixtures/qml/flea-theme/segment.qml +17 -0
  114. package/test/fixtures/qml/flea-theme/settings.qml +58 -0
  115. package/test/fixtures/qml/flea-theme/text-metrics.qml +10 -0
  116. package/test/fixtures/qml/flea-theme/ui/DialogButton.qml +150 -0
  117. package/test/fixtures/qml/flea-theme/ui/DialogField.qml +147 -0
  118. package/test/fixtures/qml/flea-theme/ui/EscapeHint.qml +11 -0
  119. package/test/fixtures/qml/flea-theme/ui/Glass.qml +114 -0
  120. package/test/fixtures/qml/flea-theme/ui/Glyph.qml +54 -0
  121. package/test/fixtures/qml/flea-theme/ui/GlyphSolid.qml +22 -0
  122. package/test/fixtures/qml/flea-theme/ui/Reveal.qml +54 -0
  123. package/test/fixtures/qml/flea-theme/ui/SettingsRuler.qml +85 -0
  124. package/test/fixtures/qml/flea-theme/ui/SettingsSegment.qml +85 -0
  125. package/test/fixtures/qml/flea-theme/ui/StableModel.qml +89 -0
  126. package/test/fixtures/qml/flea-theme/ui/Theme.qml +460 -0
  127. package/test/fixtures/qml/flea-theme/ui/ThemeColors.qml +43 -0
  128. package/test/fixtures/qml/flea-theme/ui/ViewState.qml +565 -0
  129. package/test/fixtures/qml/flea-theme/ui/js/Anchor.js +379 -0
  130. package/test/fixtures/qml/flea-theme/ui/js/AnchorHold.js +162 -0
  131. package/test/fixtures/qml/flea-theme/ui/js/Archive.js +157 -0
  132. package/test/fixtures/qml/flea-theme/ui/js/BackReturn.js +110 -0
  133. package/test/fixtures/qml/flea-theme/ui/js/Buttons.js +54 -0
  134. package/test/fixtures/qml/flea-theme/ui/js/ColumnMenu.js +111 -0
  135. package/test/fixtures/qml/flea-theme/ui/js/Columns.js +298 -0
  136. package/test/fixtures/qml/flea-theme/ui/js/Contrast.js +157 -0
  137. package/test/fixtures/qml/flea-theme/ui/js/Density.js +44 -0
  138. package/test/fixtures/qml/flea-theme/ui/js/DirSizes.js +129 -0
  139. package/test/fixtures/qml/flea-theme/ui/js/ExtThumbs.js +115 -0
  140. package/test/fixtures/qml/flea-theme/ui/js/Filter.js +284 -0
  141. package/test/fixtures/qml/flea-theme/ui/js/FolderSorts.js +108 -0
  142. package/test/fixtures/qml/flea-theme/ui/js/Format.js +305 -0
  143. package/test/fixtures/qml/flea-theme/ui/js/Icons.js +206 -0
  144. package/test/fixtures/qml/flea-theme/ui/js/Input.js +39 -0
  145. package/test/fixtures/qml/flea-theme/ui/js/KeyName.js +64 -0
  146. package/test/fixtures/qml/flea-theme/ui/js/Keymap.js +370 -0
  147. package/test/fixtures/qml/flea-theme/ui/js/Kinds.js +145 -0
  148. package/test/fixtures/qml/flea-theme/ui/js/Lists.js +11 -0
  149. package/test/fixtures/qml/flea-theme/ui/js/MakeDefault.js +186 -0
  150. package/test/fixtures/qml/flea-theme/ui/js/Match.js +27 -0
  151. package/test/fixtures/qml/flea-theme/ui/js/Material.js +109 -0
  152. package/test/fixtures/qml/flea-theme/ui/js/Menu.js +513 -0
  153. package/test/fixtures/qml/flea-theme/ui/js/Motion.js +16 -0
  154. package/test/fixtures/qml/flea-theme/ui/js/Mounts.js +320 -0
  155. package/test/fixtures/qml/flea-theme/ui/js/MouseNav.js +13 -0
  156. package/test/fixtures/qml/flea-theme/ui/js/Nav.js +328 -0
  157. package/test/fixtures/qml/flea-theme/ui/js/Palette.js +33 -0
  158. package/test/fixtures/qml/flea-theme/ui/js/Places.js +236 -0
  159. package/test/fixtures/qml/flea-theme/ui/js/Protocols.js +296 -0
  160. package/test/fixtures/qml/flea-theme/ui/js/RecentMode.js +154 -0
  161. package/test/fixtures/qml/flea-theme/ui/js/Search.js +396 -0
  162. package/test/fixtures/qml/flea-theme/ui/js/Settings.js +476 -0
  163. package/test/fixtures/qml/flea-theme/ui/js/SettingsAbout.js +99 -0
  164. package/test/fixtures/qml/flea-theme/ui/js/SettingsShelf.js +52 -0
  165. package/test/fixtures/qml/flea-theme/ui/js/Sort.js +127 -0
  166. package/test/fixtures/qml/flea-theme/ui/js/StateWords.js +42 -0
  167. package/test/fixtures/qml/flea-theme/ui/js/Swap.js +166 -0
  168. package/test/fixtures/qml/flea-theme/ui/js/TextSize.js +107 -0
  169. package/test/fixtures/qml/flea-theme/ui/js/Thumbs.js +158 -0
  170. package/test/fixtures/qml/flea-theme/ui/js/UiState.js +438 -0
  171. package/test/fixtures/qml/flea-theme/ui/js/Update.js +132 -0
  172. package/test/fixtures/qml/flea-theme/ui/js/UserDirs.js +56 -0
  173. package/test/fixtures/qml/flea-theme/ui/qmldir +227 -0
  174. package/test/fixtures/qml/hello.qml +26 -0
  175. package/test/fixtures/qml/imports/Demo/Toolkit/VersionLabel.qml +2 -0
  176. package/test/fixtures/qml/imports/Demo/Toolkit/VersionLabelNew.qml +2 -0
  177. package/test/fixtures/qml/imports/Demo/Toolkit/qmldir +3 -0
  178. package/test/fixtures/qml/imports/components/Badge.qml +15 -0
  179. package/test/fixtures/qml/imports/logic/base.js +2 -0
  180. package/test/fixtures/qml/imports/logic/counter.js +4 -0
  181. package/test/fixtures/qml/imports/logic/math.js +3 -0
  182. package/test/fixtures/qml/imports/logic/shared.js +3 -0
  183. package/test/fixtures/qml/imports/main.qml +21 -0
  184. package/test/fixtures/qml/imports/theme/Theme.qml +8 -0
  185. package/test/fixtures/qml/imports/theme/qmldir +2 -0
  186. package/test/fixtures/qml/multiply.qml +61 -0
  187. package/test/fixtures/qml-canvas-dom.js +90 -0
  188. package/test/fixtures/qml-media-audio.js +39 -0
  189. package/test/fixtures/raw-capture-benchmark.json +76 -0
  190. package/test/helpers/flea-sandbox.js +48 -0
  191. package/test/helpers/quickshell-fixture.js +125 -0
  192. package/test/html-clipboard-wayland.test.js +47 -0
  193. package/test/index.test.js +13 -0
  194. package/test/manual-casty-without-qml.js +87 -0
  195. package/test/manual-flea-application.js +49 -0
  196. package/test/manual-flea-binary.js +62 -0
  197. package/test/manual-flea-qml.js +9 -0
  198. package/test/manual-flea-settings.js +40 -0
  199. package/test/manual-flea-theme.js +40 -0
  200. package/test/manual-qml-removal.js +46 -0
  201. package/test/manual-without-qml.js +45 -0
  202. package/test/qml-canvas-dom.test.js +37 -0
  203. package/test/qml-clipboard-bridge.test.js +25 -0
  204. package/test/qml-clipboard-wayland.test.js +40 -0
  205. package/test/qml-connections-timing.test.js +73 -0
  206. package/test/qml-dynamic.test.js +401 -0
  207. package/test/qml-flea-app.test.js +146 -0
  208. package/test/qml-flea-backend.test.js +78 -0
  209. package/test/qml-flea-columns-backend.test.js +38 -0
  210. package/test/qml-flea-compile.test.js +78 -0
  211. package/test/qml-flea-launcher.test.js +88 -0
  212. package/test/qml-flea-markdown-backend.test.js +31 -0
  213. package/test/qml-flea-media.test.js +28 -0
  214. package/test/qml-flea-navigation-backend.test.js +35 -0
  215. package/test/qml-flea-navigation-timing.test.js +147 -0
  216. package/test/qml-flea-preview-backend.test.js +53 -0
  217. package/test/qml-flea-previews.test.js +163 -0
  218. package/test/qml-flea-rows.test.js +101 -0
  219. package/test/qml-flea-textures.test.js +59 -0
  220. package/test/qml-flea-view-switch.test.js +33 -0
  221. package/test/qml-flea-wayland.test.js +68 -0
  222. package/test/qml-flea.test.js +34 -0
  223. package/test/qml-host.test.js +238 -0
  224. package/test/qml-imports.test.js +102 -0
  225. package/test/qml-inherited-handlers.test.js +51 -0
  226. package/test/qml-input-selection.test.js +66 -0
  227. package/test/qml-interactions.test.js +309 -0
  228. package/test/qml-language.test.js +167 -0
  229. package/test/qml-launcher.test.js +54 -0
  230. package/test/qml-layout-text.test.js +205 -0
  231. package/test/qml-media.test.js +63 -0
  232. package/test/qml-persisted-delegates.test.js +45 -0
  233. package/test/qml-quickshell-controls.test.js +65 -0
  234. package/test/qml-quickshell-settings.test.js +62 -0
  235. package/test/qml-repeater.test.js +72 -0
  236. package/test/qml-style-updates.test.js +124 -0
  237. package/test/qml-textures.test.js +66 -0
  238. package/test/qml-views.test.js +332 -0
  239. package/test/qml-worker.test.js +69 -0
  240. package/test/qml.test.js +83 -0
  241. package/test/raw-capture.test.js +152 -0
  242. package/test/renderer-host.test.js +11 -0
  243. package/test/text-input-pointer.test.js +31 -0
  244. package/test/text-input-scroll.test.js +29 -0
  245. package/test/text-input.test.js +47 -0
  246. package/test/wayland-frontend.test.js +83 -0
  247. package/test/wayland-urlbar.test.js +38 -0
  248. package/test/window-resize.test.js +36 -0
  249. package/tools/bench-raw-capture.js +32 -0
@@ -0,0 +1,118 @@
1
+ pragma Singleton
2
+ import QtQuick
3
+ import Quickshell
4
+ import Quickshell.Io
5
+ import "Plural.js" as Plural
6
+ import "Numbers.js" as Numbers
7
+
8
+ // Display-language strings for the shell. The selected code lives in
9
+ // ~/.config/omarchy/language (omarchy-language owns it); a missing file
10
+ // means English. Strings come from default/i18n/<code>/shell.json layered
11
+ // over the English catalog, so a missing translation falls back to English
12
+ // per string. Use as I18n.t("common.search"), with .arg(...) for %1 holes,
13
+ // and I18n.tn(key, count).arg(I18n.formatNumber(count)) for an
14
+ // entry with plural forms.
15
+ // The language file is watched, so switching language under Setup
16
+ // re-renders the shell without a restart.
17
+ QtObject {
18
+ id: root
19
+
20
+ readonly property string omarchyPath: Quickshell.env("OMARCHY_PATH")
21
+ readonly property string configHome: Quickshell.env("XDG_CONFIG_HOME") || (Quickshell.env("HOME") + "/.config")
22
+
23
+ readonly property string language: languageCode(languageFile.text())
24
+ readonly property var localeSettings: parseCatalog(registryFile.text())[root.language] || ({})
25
+ readonly property string formatLocale: localeSettings.formatLocale || "en-US"
26
+ // From the registry: how numbers are written and which way text runs.
27
+ readonly property string decimal: localeSettings.decimal || "."
28
+ readonly property string zeroDigit: localeSettings.zeroDigit || "0"
29
+ readonly property bool rightToLeft: localeSettings.direction === "rtl"
30
+
31
+ // Reading text() makes blockLoading take effect on the first lookup.
32
+ // These bindings also rebuild the maps when a watched catalog changes.
33
+ readonly property var englishStrings: parseCatalog(englishCatalogFile.text())
34
+ readonly property var languageStrings: parseCatalog(languageCatalogFile.text())
35
+ readonly property var strings: {
36
+ var merged = ({})
37
+ for (var k in root.englishStrings) merged[k] = root.englishStrings[k]
38
+ for (var k2 in root.languageStrings) merged[k2] = root.languageStrings[k2]
39
+ return merged
40
+ }
41
+
42
+ // The optional fallback is what imperative callers (the JS models) pass
43
+ // as their English text: for a key the catalogs do not carry, they keep
44
+ // sensible English instead of a raw key.
45
+ function t(key, fallback) {
46
+ var value = root.strings[key]
47
+ if (value && typeof value === "object") value = value.other
48
+ if (typeof value === "string" && value.length > 0) return value
49
+ return fallback !== undefined ? fallback : key
50
+ }
51
+
52
+ // The form of a plural entry for count, by the language's plural rules
53
+ // (Plural.js). The English entry answers when the translation has none.
54
+ function tn(key, count, fallback) {
55
+ var value = Plural.pick(root.languageStrings[key], root.language, count)
56
+ if (typeof value !== "string" || value.length === 0) value = Plural.pick(root.englishStrings[key], "en", count)
57
+ if (typeof value === "string" && value.length > 0) return value
58
+ return fallback !== undefined ? fallback : key
59
+ }
60
+
61
+ // A number with the language's decimal separator and digits, ungrouped:
62
+ // formatNumber(13.14, 1) is "13,1" in Danish. Pass decimals to round;
63
+ // without them the value is written as it is.
64
+ function formatNumber(value, decimals) {
65
+ return Numbers.format(value, decimals, root.decimal, root.zeroDigit)
66
+ }
67
+
68
+ function parseCatalog(raw) {
69
+ try {
70
+ var parsed = JSON.parse(raw || "{}")
71
+ return (parsed && typeof parsed === "object" && !Array.isArray(parsed)) ? parsed : ({})
72
+ } catch (e) {
73
+ return ({})
74
+ }
75
+ }
76
+
77
+ function languageCode(raw) {
78
+ var code = String(raw || "").trim()
79
+ if (!/^[a-z]{2,3}(-[A-Za-z]{2})?$/.test(code)) code = "en"
80
+ return code
81
+ }
82
+
83
+ // The catalogs are small local files, read synchronously so the first
84
+ // binding to call t() already gets the string rather than the raw key.
85
+ property FileView languageFile: FileView {
86
+ // OMARCHY_LANGUAGE_FILE overrides the location, as it does for
87
+ // omarchy-i18n, so tests can pin a language whatever the machine uses.
88
+ path: Quickshell.env("OMARCHY_LANGUAGE_FILE") || (root.configHome + "/omarchy/language")
89
+ watchChanges: true
90
+ printErrors: false
91
+ blockLoading: true
92
+ onFileChanged: reload()
93
+ }
94
+
95
+ property FileView englishCatalogFile: FileView {
96
+ path: root.omarchyPath + "/default/i18n/en/shell.json"
97
+ watchChanges: true
98
+ printErrors: false
99
+ blockLoading: true
100
+ onFileChanged: reload()
101
+ }
102
+
103
+ property FileView languageCatalogFile: FileView {
104
+ path: root.omarchyPath + "/default/i18n/" + root.language + "/shell.json"
105
+ watchChanges: true
106
+ printErrors: false
107
+ blockLoading: true
108
+ onFileChanged: reload()
109
+ }
110
+
111
+ property FileView registryFile: FileView {
112
+ path: root.omarchyPath + "/default/i18n/locales.json"
113
+ watchChanges: true
114
+ printErrors: false
115
+ blockLoading: true
116
+ onFileChanged: reload()
117
+ }
118
+ }
@@ -0,0 +1,19 @@
1
+ // A number written with a language's decimal separator and digits from the
2
+ // registry, ungrouped: format(13.14, 1, ",", "0") is "13,1". Without
3
+ // decimals the value is written as it is. default/i18n/plural.jq's
4
+ // localize_number does the same for omarchy-i18n.
5
+ function format(value, decimals, decimal, zeroDigit) {
6
+ var number = Number(value)
7
+ if (!isFinite(number)) return String(value)
8
+ var text = decimals === undefined ? String(number) : number.toFixed(decimals)
9
+ if (decimal && decimal !== ".") text = text.replace(".", decimal)
10
+ if (zeroDigit && zeroDigit !== "0") {
11
+ var zero = zeroDigit.charCodeAt(0)
12
+ text = text.replace(/[0-9]/g, function(digit) { return String.fromCharCode(zero + digit.charCodeAt(0) - 48) })
13
+ }
14
+ return text
15
+ }
16
+
17
+ if (typeof module !== "undefined") {
18
+ module.exports = { format: format }
19
+ }
@@ -0,0 +1,91 @@
1
+ // CLDR cardinal plural categories for whole counts, per Omarchy language
2
+ // code. A plural catalog entry is an object keyed by these categories
3
+ // ({ "one": "%1 file", "other": "%1 files" }); every language needs "other",
4
+ // plus whichever categories its counts can reach. default/i18n/plural.jq
5
+ // holds the same rules for omarchy-i18n, and i18n-test.sh keeps the two
6
+ // in agreement.
7
+
8
+ function within(value, low, high) {
9
+ return value >= low && value <= high
10
+ }
11
+
12
+ function category(code, count) {
13
+ var n = Math.abs(Math.trunc(Number(count) || 0))
14
+ var n10 = n % 10
15
+ var n100 = n % 100
16
+ var millions = n !== 0 && n % 1000000 === 0
17
+
18
+ switch (String(code || "")) {
19
+ case "ja": case "ko": case "zh-CN": case "zh-TW": case "th": case "vi": case "id": case "ms":
20
+ return "other"
21
+ case "hi": case "bn": case "fa": case "si":
22
+ return n <= 1 ? "one" : "other"
23
+ case "fr": case "pt-BR":
24
+ return n <= 1 ? "one" : millions ? "many" : "other"
25
+ case "ca": case "es-MX": case "it": case "pt":
26
+ return n === 1 ? "one" : millions ? "many" : "other"
27
+ case "fil":
28
+ return (n10 === 4 || n10 === 6 || n10 === 9) ? "other" : "one"
29
+ case "is":
30
+ return n10 === 1 && n100 !== 11 ? "one" : "other"
31
+ case "cs": case "sk":
32
+ return n === 1 ? "one" : within(n, 2, 4) ? "few" : "other"
33
+ case "pl":
34
+ if (n === 1) return "one"
35
+ return within(n10, 2, 4) && !within(n100, 12, 14) ? "few" : "many"
36
+ case "ru": case "uk":
37
+ if (n10 === 1 && n100 !== 11) return "one"
38
+ return within(n10, 2, 4) && !within(n100, 12, 14) ? "few" : "many"
39
+ case "hr": case "sr":
40
+ if (n10 === 1 && n100 !== 11) return "one"
41
+ return within(n10, 2, 4) && !within(n100, 12, 14) ? "few" : "other"
42
+ case "sl":
43
+ if (n100 === 1) return "one"
44
+ if (n100 === 2) return "two"
45
+ return within(n100, 3, 4) ? "few" : "other"
46
+ case "lt":
47
+ if (within(n100, 11, 19)) return "other"
48
+ return n10 === 1 ? "one" : n10 >= 2 ? "few" : "other"
49
+ case "lv":
50
+ if (n10 === 0 || within(n100, 11, 19)) return "zero"
51
+ return n10 === 1 ? "one" : "other"
52
+ case "ro":
53
+ if (n === 1) return "one"
54
+ return n === 0 || within(n100, 1, 19) ? "few" : "other"
55
+ case "ar":
56
+ if (n <= 2) return ["zero", "one", "two"][n]
57
+ return within(n100, 3, 10) ? "few" : within(n100, 11, 99) ? "many" : "other"
58
+ case "he":
59
+ return n === 1 ? "one" : n === 2 ? "two" : "other"
60
+ case "ga":
61
+ if (n <= 2) return n === 0 ? "other" : n === 1 ? "one" : "two"
62
+ return within(n, 3, 6) ? "few" : within(n, 7, 10) ? "many" : "other"
63
+ default:
64
+ return n === 1 ? "one" : "other"
65
+ }
66
+ }
67
+
68
+ var ORDER = ["zero", "one", "two", "few", "many", "other"]
69
+
70
+ // The categories a translation of a plural entry must provide.
71
+ function categories(code) {
72
+ var seen = { other: true }
73
+ for (var n = 0; n <= 1000; n++) seen[category(code, n)] = true
74
+ seen[category(code, 1000000)] = true
75
+ return ORDER.filter(function(name) { return seen[name] })
76
+ }
77
+
78
+ // The string for a count from a plural entry, or the entry itself when it
79
+ // is a plain string. A translation missing a category falls back to its
80
+ // "other" form.
81
+ function pick(entry, code, count) {
82
+ if (typeof entry === "string") return entry
83
+ if (!entry || typeof entry !== "object") return undefined
84
+ var form = entry[category(code, count)]
85
+ if (typeof form === "string" && form.length > 0) return form
86
+ return typeof entry.other === "string" ? entry.other : undefined
87
+ }
88
+
89
+ if (typeof module !== "undefined") {
90
+ module.exports = { category: category, categories: categories, pick: pick }
91
+ }