Compare commits

...

273 Commits

Author SHA1 Message Date
Raphaël Jakse 2c1716827e credits 2021-08-05 11:24:16 +02:00
Raphaël Jakse 286ad54c47 new bag (thanks Ysabeau) 2021-08-05 11:19:19 +02:00
Laurent Mazet ac72c674e6 premium depends on board definition 2021-05-24 22:57:23 +02:00
Laurent Mazet 716abf5da7 I gave up for 25x25-6 and 19x25-6 board 2021-05-24 22:41:24 +02:00
Laurent Mazet da8f9e659d add board 25x25-8 2021-05-24 22:38:39 +02:00
Laurent Mazet 49889593cf add board 9x25-8 2021-05-02 08:41:10 +02:00
Laurent Mazet 190f4e3c4e add board 9x17-8 2021-05-02 08:40:34 +02:00
Laurent Mazet edba0b22d3 add board 8x15-7 2021-05-01 21:47:12 +02:00
Laurent Mazet fecf8559e9 add board 9x9-8 2021-05-01 14:52:41 +02:00
Laurent Mazet c735b917a3 reorder boards by size 2021-05-01 14:41:51 +02:00
Laurent Mazet c3565b1599 correct factor for board 19x19-6 2021-04-29 23:08:59 +02:00
Laurent Mazet 351bb73cd2 add board 19x19-6 2021-04-29 23:06:14 +02:00
Laurent Mazet 7141abd67e correct board 15x15-7 2021-04-29 23:05:38 +02:00
Laurent Mazet 74973874f2 fix eslint issues 2021-04-28 22:44:03 +02:00
Laurent Mazet 9b0ea1f0a8 better board and rack cleaning 2021-04-28 22:42:57 +02:00
Laurent Mazet 2e681a9c0b correct bound checking 2021-04-28 22:40:47 +02:00
Laurent Mazet 71df36594d fix initial setting 2021-04-27 09:51:13 +02:00
Laurent Mazet 27f010fc8c Warm only once per session 2021-04-27 00:07:07 +02:00
Laurent Mazet 857c7fb6d0 add new boards 2021-04-26 23:50:13 +02:00
Laurent Mazet fac4ebf1a4 make custom board an experimental feature 2021-04-26 21:59:18 +02:00
Laurent Mazet 8b6bcf3a19 change label to configuration 2021-04-26 21:37:02 +02:00
Laurent Mazet 6398be6b9a Merge branch 'develop' into custon_board_layout 2021-04-26 20:57:32 +02:00
Raphaël Jakse 9ef26b56ad Merge branch 'fix_on_change_cell_caption_callback' into 'develop'
Fix 'on change' cell caption callback

See merge request raphj/trivabble!26
2021-04-26 15:56:19 +00:00
Laurent Mazet 1745df77f7 correct PORT setting 2021-04-26 08:45:16 +02:00
Laurent Mazet bfd0267d6e implement bag factor 2021-04-26 08:44:59 +02:00
Laurent Mazet df930fa374 set mode variable 2021-04-26 06:22:31 +02:00
Laurent Mazet 6c520e63ce duplicated type definition 2021-04-26 06:17:47 +02:00
Laurent Mazet e24f694a1e fix error from develop (mode does not exists) and set cell captions after drawing board 2021-04-24 22:09:49 +02:00
Laurent Mazet 915f84a4ff Merge branch 'develop' into custon_board_layout 2021-04-24 21:48:11 +02:00
Raphaël Jakse 516f66e0b3 Don't set cell caption setting on load 2021-04-24 21:29:15 +02:00
Laurent Mazet b6682f2b19 fix issue when PlayerName is empty 2021-04-24 20:54:24 +02:00
Laurent Mazet a6ed305972 Merge remote-tracking branch 'fork/cell_caption_option' into cell_caption_option 2021-04-24 13:50:59 +02:00
Laurent Mazet bccce721d3 fix issue 2021-04-24 13:50:13 +02:00
Laurent Mazet f817c0b5ab new board can be rectangular and rack length can be changed 2021-04-24 10:59:57 +02:00
Laurent Mazet d51ae94441 add new boards (8x8 and 22x22) 2021-04-23 00:01:03 +02:00
Laurent Mazet e6f4d09c9a Apply 1 suggestion(s) to 1 file(s) 2021-04-21 19:31:53 +00:00
Laurent Mazet 36876cf697 Apply 1 suggestion(s) to 1 file(s) 2021-04-21 19:31:43 +00:00
Laurent Mazet 8c5c06e543 translations 2021-04-21 11:33:18 +02:00
Laurent Mazet 657ac8c175 fix eslint error 2021-04-21 10:46:19 +02:00
Laurent Mazet fa58416e05 Merge branch 'develop' into cell_caption_option 2021-04-21 10:45:03 +02:00
Laurent Mazet 2af43c8ad8 Revert "fix eslint errors"
This reverts commit 8f674f3848.
2021-04-21 10:44:38 +02:00
Laurent Mazet 8f674f3848 fix eslint errors 2021-04-20 22:13:09 +02:00
Laurent Mazet afba7b12c4 reorder SettingTypes and remove unused Timer 2021-04-20 22:06:35 +02:00
Laurent Mazet 01f622854a remove unused config ENABLE_SPELL_CHECKER 2021-04-20 22:04:10 +02:00
Laurent Mazet 291005d150 remove TimerEnable key 2021-04-20 21:59:33 +02:00
Laurent Mazet c118fd652e remove CellCaptions key 2021-04-20 21:57:50 +02:00
Laurent Mazet 9c2408c560 only store values that differ from defaults 2021-04-20 14:13:58 +02:00
Laurent Mazet 3384a8c1f7 remove direct call to Conf structure 2021-04-20 08:43:27 +02:00
Laurent Mazet b010c4c43e clean default configuration 2021-04-20 08:31:22 +02:00
Raphaël Jakse f69adfee53 update the main website URL 2021-03-14 20:06:35 +01:00
Raphaël Jakse 1410b41216 Merge branch 'fix_eslint_erros_from_timer' into 'develop'
Fix eslint errors from timer branch

See merge request raphj/trivabble!24
2021-01-20 18:33:20 +00:00
Laurent Mazet 6cee6fbf91 fix eslint errors 2021-01-18 22:46:46 +01:00
Laurent Mazet 3a148fbbd1 fix central star 2021-01-15 18:39:29 +01:00
Laurent Mazet ae79bb84b8 Limit changes on cell text content 2021-01-15 18:36:36 +01:00
Laurent Mazet 7bd9b6c16b add class to board instead of cells 2021-01-15 18:20:52 +01:00
Laurent Mazet aaa1c92ac8 default value for CELL_CAPTIONS 2020-12-28 11:29:53 +01:00
Laurent Mazet b0eff630ff various fixes 2020-12-28 11:29:17 +01:00
Laurent Mazet b1dade8bb9 add a rule for tidy checker 2020-12-28 10:53:05 +01:00
Laurent Mazet aa595353ac New option for caption 2020-12-23 21:52:09 +01:00
Raphaël Jakse 2bcac05534 Merge branch 'timer' into 'develop'
Timer

See merge request raphj/trivabble!11
2020-12-12 12:18:16 +00:00
Raphaël Jakse 235d51c802 fix timer day translation 2020-12-12 11:01:46 +01:00
Raphaël Jakse 94650bf219 Timer next to the settings button 2020-12-12 10:49:58 +01:00
Laurent Mazet 7bdd46d2ff Third design 2020-12-10 21:30:47 +01:00
Laurent Mazet 91799047ad Add a tip 2020-12-09 22:56:35 +01:00
Laurent Mazet b0e5c8aede Better strings 2020-12-09 22:41:07 +01:00
Raphaël Jakse 7297e2de2e Design improvement 2020-12-09 22:30:42 +01:00
Laurent Mazet 8f9ed16bce disactivate timers by default 2020-12-08 21:37:47 +01:00
Laurent Mazet 94feed71b6 stylish timers 2020-12-08 21:18:01 +01:00
Laurent Mazet 9c7a3b3e2a remove localStorage usage 2020-12-07 22:28:39 +01:00
Laurent Mazet b059eaf9e9 Merge branch 'develop' into timer 2020-12-06 17:59:03 +01:00
Raphaël Jakse 4ebba1af7c Merge branch 'fix-non-rectangular-board' into 'develop'
Fix non rectangular board

See merge request raphj/trivabble!22
2020-12-06 16:35:49 +00:00
Raphaël Jakse 0bd24691d3 Merge branch 'automatic_scoring' into 'develop'
Automatic scoring

See merge request raphj/trivabble!13
2020-12-06 16:31:39 +00:00
Laurent Mazet 40ce2c15a3 better score check 2020-11-24 13:26:52 +01:00
Laurent Mazet a6d3dc6ed8 use a local variable to store player's name 2020-11-24 13:21:39 +01:00
Laurent Mazet 899cb609fa fix regression in alert window 2020-11-24 08:01:16 +01:00
Laurent Mazet 7d4301636f reset list of moved tiles after scoring 2020-11-23 22:45:30 +01:00
Laurent Mazet f5f53ac7a8 add an option to select who scores: last player or player who pressed on the button 2020-11-23 22:44:24 +01:00
Raphaël Jakse 8fce6213ca lint 2020-11-22 22:55:24 +01:00
Raphaël Jakse e3b4fc0b7e who messed up? 2020-11-22 22:20:43 +01:00
Raphaël Jakse 6c263c2976 score by default the last player who played 2020-11-22 21:54:44 +01:00
Raphaël Jakse 54d46706b0 some refinements on the auto counting feature 2020-11-22 12:28:42 +01:00
Raphaël Jakse e69a279eec handle overflow in cells 2020-11-22 12:28:07 +01:00
Laurent Mazet e9a1a3aa04 Merge branch 'develop' into automatic_scoring 2020-11-22 12:19:36 +01:00
Raphaël Jakse 66c3d65f2b use getSetting for API_ENTRY_POINT 2020-11-22 11:17:40 +01:00
Laurent Mazet 540e5e8920 fix cancel 2020-11-19 21:30:23 +01:00
Laurent Mazet 9d041e812e Merge branch 'develop' into automatic_scoring 2020-11-19 07:34:38 +01:00
Laurent Mazet ea2485f71d add a selector to choice player 2020-11-17 22:50:57 +01:00
Laurent Mazet b28dc47089 update confirmation message 2020-11-16 11:22:37 +01:00
Raphaël Jakse d74fa69464 Make API_ENTRY_POINT configurable 2020-11-14 11:02:50 +01:00
Raphaël Jakse dddee16ee5 fix disableCSP 2020-10-27 08:20:57 +01:00
Laurent Mazet 4ddd84885b make premium for playing seven tiles configurable (system wide) 2020-10-23 21:40:16 +02:00
Laurent Mazet e6df1604e9 Correct message 2020-10-23 21:31:30 +02:00
Laurent Mazet 7dfbc74d38 Apply 1 suggestion(s) to 1 file(s) 2020-10-22 20:01:21 +00:00
Laurent Mazet c7407670de Merge branch 'develop' into automatic_scoring 2020-10-22 21:26:09 +02:00
Raphaël Jakse 9023d3a86d Merge branch 'various_issues_with_dictionaries' into 'develop'
Various issues with dictionaries

See merge request raphj/trivabble!21
2020-10-21 19:07:18 +00:00
Laurent Mazet 121d1422ef Various issues with dictionaries 2020-10-21 19:07:18 +00:00
Laurent Mazet 6c74d77a97 avoid error when currentPlayer is not set 2020-10-18 20:49:12 +02:00
Laurent Mazet 1ca1b4ad7c add French translation 2020-10-18 19:25:51 +02:00
Laurent Mazet faf78ca932 Merge branch 'develop' into automatic_scoring 2020-10-18 19:21:36 +02:00
Raphaël Jakse 8d50eadc78 Add unsecable space in French translation 2020-10-17 09:33:06 +02:00
Raphaël Jakse 943d62f482 ignore dictionary files 2020-10-17 08:10:24 +02:00
Raphaël Jakse de5d32d43a Merge branch 'remove_spellckecker_button_if_no_dictionary_avaliable-2' into 'develop'
Avoid display spell checker if there is no dictionary

See merge request raphj/trivabble!20
2020-10-16 19:50:46 +00:00
Raphaël Jakse ba4631e3dd drop ENABLE_SPELL_CHECKER 2020-10-16 18:34:01 +02:00
Laurent Mazet b23f70ea31 fix eslint error 2020-10-16 10:19:47 +02:00
Laurent Mazet 356a2ef7d8 avoid display spell checker if there is no dictionary 2020-10-16 08:05:51 +02:00
Raphaël Jakse 7105d495f7 Merge branch 'fix_ukrainian_tiles' into 'develop'
replace the joker tiles by blank tiles

See merge request raphj/trivabble!18
2020-10-09 22:22:52 +00:00
Laurent Mazet 76d4ecaf36 replace the joker tiles by blank tiles 2020-10-09 22:14:04 +02:00
Raphaël Jakse 10c12f97a4 Document CSP 2020-10-09 00:14:57 +02:00
Raphaël Jakse 1f9e062014 Fix fragile tile position lookup
This code didn't work when Trivabble was served as text/html, which adds
a <tbody> tag in the DOM, while this tag is not added when Trivabble is
served as application/xhtml+xml.
2020-10-08 22:03:56 +02:00
Raphaël Jakse cdd2ca777a Fix settings and unset SpellCheckerEnabledOnce when disabling the spell checker 2020-10-08 18:43:05 +02:00
Raphaël Jakse 6fdfc05437 Lint 2020-10-07 22:02:21 +02:00
Laurent Mazet 82b38df25d correct board design 2020-10-07 22:01:08 +02:00
Raphaël Jakse c5ccb93eef Force declaring the setting types and stop storing them in localStorage 2020-10-07 21:48:30 +02:00
Raphaël Jakse 930fc12939 fix first WebSocket connection 2020-10-07 21:30:04 +02:00
Raphaël Jakse 85b0bd04a0 add a 'disable spell checker' checkbox and rename settings 2020-10-07 20:16:36 +02:00
Laurent Mazet 12cc95b700 Merge branch 'develop' into timer 2020-10-06 11:48:25 +02:00
Raphaël Jakse 06d7d0b117 Fix support for Safari 8+ 2020-10-05 23:47:06 +02:00
Raphaël Jakse cc28f3683e Fix the empty rack button 2020-10-05 23:46:47 +02:00
Raphaël Jakse 10c8868742 Lint 2020-10-05 21:38:34 +02:00
Raphaël Jakse 289d879781 Improve the settings dialog
- Presentation a bit clearer.
- closing with escape now uses an event handler on window instead of body.
  Chromium didn't like the latter.
- Improve the keyboard navigation
2020-10-05 21:35:02 +02:00
Raphaël Jakse f77cf3197e Remove the "enable spell checker" checkbox
I don't really see a use case requiring disabling the spell checker if available.
People can just not use it. The dictionary is downloaded on first use anyway.
We do want people to discover the feature with the presence of the related button
by default, however.
2020-10-05 20:54:33 +02:00
Raphaël Jakse 2fd1b2672c branding - thanks Ysabeau for the logo 2020-10-05 20:42:31 +02:00
Raphaël Jakse 4c840fff52 hack: prevent error messages from resizing the chat box 2020-10-03 12:33:24 +02:00
Raphaël Jakse 191fc7c69e get rid of inline styles 2020-10-03 12:27:16 +02:00
Raphaël Jakse 02e8d3f6a5 Various improvements
- soften buttons a bit
- align the lang settings
- ensure paddings are okay at various places
- make the escape key close various dialogs
- make some settings even more flexible (for the admin sys)
- do not save the new value of a setting if its value is already equal to this.

- change the default flash light color
2020-10-03 11:18:24 +02:00
Raphaël Jakse 26b2c9d206 Merge branch 'lmazet/trivabble-help_message' into develop 2020-10-03 10:07:43 +02:00
Laurent Mazet 68d00c4839 change width box for help message to auto 2020-09-28 22:35:52 +02:00
Laurent Mazet 8ff7a80b33 Merge branch 'develop' into timer 2020-09-28 22:28:45 +02:00
Raphaël Jakse b6eaba6d21 Work on the presentation of the tip help box 2020-09-28 20:40:49 +02:00
Raphaël Jakse 8fbc589ffe Merge branch 'minimize_localstorage' into 'develop'
Minimize localstorage

See merge request raphj/trivabble!14
2020-09-28 16:03:29 +00:00
Raphaël Jakse 6878bebcd4 Merge branch 'doc-nginx' into 'develop'
Documentation for nginx

See merge request raphj/trivabble!12
2020-09-28 16:03:03 +00:00
Laurent Mazet 40a8961622 add a button to change message 2020-09-22 19:02:14 +02:00
Laurent Mazet 96b2721a0d help message delay is configurable 2020-09-15 22:55:38 +02:00
Laurent Mazet 5a4eda81f0 help messages change every 10s 2020-09-15 22:53:04 +02:00
Laurent Mazet c899147c78 clean help messages 2020-09-15 22:52:36 +02:00
Raphaël Jakse 0e19459687 readme: add wget in the section regarding the dictionaries 2020-09-15 08:09:07 +02:00
Laurent Mazet 373877be35 migrate all settings 2020-09-14 07:54:40 +02:00
Laurent Mazet 7466a91def fix type checking 2020-09-13 22:57:48 +02:00
Laurent Mazet 6ebcc0284d correct eslint errors 2020-09-13 22:46:43 +02:00
Laurent Mazet 549b176ac9 remove duplicated function 2020-09-13 22:39:31 +02:00
Laurent Mazet 830da2b15c migrate old settings for tiles and messages sound enablers 2020-09-13 22:38:40 +02:00
Laurent Mazet db81c3e00c add default values for tiles and messages sound enablers 2020-09-13 22:37:33 +02:00
Laurent Mazet aee069d6f8 correct boolean type 2020-09-13 22:09:16 +02:00
Laurent Mazet 94a76b3f5c Apply 1 suggestion(s) to 1 file(s) 2020-09-13 10:00:32 +00:00
Laurent Mazet 677724b76c avoid string true for boolean variable 2020-09-13 11:39:40 +02:00
Laurent Mazet 754e1770a5 remove support for bigint 2020-09-13 11:36:49 +02:00
Laurent Mazet ae9c2a7da3 use setting functions 2020-09-10 08:04:40 +02:00
Laurent Mazet 9f499f11b3 reindent configuration default values 2020-09-10 08:04:11 +02:00
Laurent Mazet 92329580b2 correct setting functions 2020-09-10 08:03:45 +02:00
Laurent Mazet 64c1ebff0c new functions getSetting and setSetting 2020-09-09 07:32:48 +02:00
Laurent Mazet 6fcd9371fd fix eslint errors 2020-09-07 22:42:14 +02:00
Laurent Mazet 1f53f79e83 add translation 2020-09-07 22:35:45 +02:00
Laurent Mazet fddf7ee8f3 add score to current player 2020-09-07 22:32:51 +02:00
Laurent Mazet 2ddb56a06d initial scoring function 2020-09-07 10:31:53 +02:00
Raphaël Jakse 2f4dbb6af5 Document configuration for Nginx 2020-09-05 08:47:23 +02:00
Laurent Mazet b111728781 split settings into differents divs 2020-09-05 08:24:17 +02:00
Laurent Mazet a58dd247ad Merge branch 'develop' into timer 2020-09-05 08:20:50 +02:00
Raphaël Jakse 9c0b1d068e Merge branch 'laser_pointer' into 'develop'
Laser pointer

See merge request raphj/trivabble!10
2020-09-05 05:56:52 +00:00
Raphaël Jakse f43f9811c2 make laser double tap work on mobile browsers 2020-09-04 22:10:21 +02:00
Raphaël Jakse d5f4d913db fix dblckick on tile in Chromium 2020-09-03 23:04:59 +02:00
Raphaël Jakse ad5ac4f2e6 laser: highlight tiles, too 2020-09-01 23:43:03 +02:00
Raphaël Jakse 8d0d22c4d1 attach the laser event handlers to body 2020-09-01 22:45:55 +02:00
Laurent Mazet d4eff0783a cast timers into numbers 2020-09-01 21:19:45 +02:00
Laurent Mazet 65d7ca684a use date differents instead of interval increments 2020-08-30 21:40:57 +02:00
Laurent Mazet 344bae18a2 Merge branch 'develop' into laser_pointer 2020-08-30 21:24:02 +02:00
Laurent Mazet 752c352f43 replace innerHTML by textContent 2020-08-29 23:06:31 +02:00
Laurent Mazet 16b7eb4185 Merge branch 'develop' into timer 2020-08-29 23:03:57 +02:00
Laurent Mazet 3960e9d51e change timer format 2020-08-29 22:23:45 +02:00
Raphaël Jakse 78c135de1c work on settings and spell checker UI/UX 2020-08-29 12:26:05 +02:00
Raphaël Jakse c2108dd441 document and optimise the dictionary build process a bit 2020-08-29 10:54:52 +02:00
Laurent Mazet 364b9bbe30 change input to range for durations 2020-08-19 21:47:00 +02:00
Laurent Mazet c8ba514540 correct turn timer reset 2020-08-18 14:38:35 +02:00
Laurent Mazet bb42d5491d fix eslint errors 2020-08-18 14:34:42 +02:00
Laurent Mazet c05cc78677 add translations 2020-08-18 13:49:27 +02:00
Laurent Mazet 58c042375a make timer configurable 2020-08-18 13:44:25 +02:00
Laurent Mazet 44da72c591 add timer 2020-08-18 13:29:37 +02:00
Laurent Mazet 9b0c2f559e remove hu dictionary from the list of small dictionary because it is VERY huge 2020-08-16 19:03:16 +02:00
Laurent Mazet a9de7c881f fix eslint errors 2020-08-14 21:35:25 +02:00
Laurent Mazet 96a11e32ce fix init spell checker 2020-08-14 14:28:38 +02:00
Laurent Mazet 0d96b978b0 add a translation 2020-08-14 14:17:16 +02:00
Laurent Mazet c5ef9ac5b3 move out dictionary objet files from working directory 2020-08-14 14:06:49 +02:00
Laurent Mazet a87aaa5a09 add a rule to create required files 2020-08-14 10:55:44 +02:00
Laurent Mazet 8d927835d3 add spell checker enabler into configuration window 2020-08-14 10:54:16 +02:00
Laurent Mazet 9eff9ef527 Merge branch 'develop' into check_spelling 2020-08-13 11:41:32 +02:00
Laurent Mazet fee072d2b8 simplify string concatenation 2020-08-13 10:00:40 +02:00
Laurent Mazet 4d1a4ab4c8 fix eslint errors 2020-08-13 09:58:35 +02:00
Laurent Mazet 09dafa5cb7 make flash light color configurable 2020-08-13 09:36:32 +02:00
Laurent Mazet 9633392b4c fix center cell 2020-08-13 09:06:55 +02:00
Laurent Mazet 726fae2d07 extra line 2020-08-12 22:27:27 +02:00
Laurent Mazet 18de97b29d correct eslint errors 2020-08-12 22:10:51 +02:00
Laurent Mazet 520cb28445 add translations 2020-08-12 21:56:40 +02:00
Laurent Mazet a0df72a53a make durations (double tap and flash light) configurable 2020-08-12 21:56:17 +02:00
Laurent Mazet f9a41185e1 make flash light duration parametric 2020-08-12 08:00:27 +02:00
Laurent Mazet 6872d289fe Merge branch 'develop' into laser_pointer 2020-08-12 07:46:35 +02:00
Raphaël Jakse e9d13c9e44 Merge branch 'configuration_dialog' into 'develop'
Add a configuration dialog (issue #10)

See merge request raphj/trivabble!9
2020-08-11 21:29:00 +00:00
Laurent Mazet 1b83772b03 Merge branch 'master' into configuration_dialog 2020-08-04 22:46:46 +02:00
Laurent Mazet f427c050e5 Add translations 2020-08-04 14:53:09 +02:00
Laurent Mazet 166ac08f0b simplify configuration window 2020-08-04 14:52:32 +02:00
Laurent Mazet fcd99ce146 dialog window for configuration options 2020-08-03 14:11:23 +02:00
Laurent Mazet 9ee161fd64 fix eslint errors 2020-07-22 08:04:09 +02:00
Laurent Mazet 0be339cf2d fix enable-spell-checker button state 2020-07-22 07:50:35 +02:00
Laurent Mazet 201a9c2a6d desactivate laser pointer on tile (only avaliable for desktop firefox) 2020-07-21 22:24:05 +02:00
Laurent Mazet ff8bb5ce49 add a laser pointer to highlight a case 2020-07-21 22:12:25 +02:00
Raphaël Jakse 08a7890bf7 fix alert placement on iPad 2 2020-07-13 15:54:09 +02:00
Raphaël Jakse 921e2f620d fix incorrect host display in the server 2020-07-13 15:53:45 +02:00
Raphaël Jakse 620af09719 wider '+' button to set the score 2020-07-13 15:53:45 +02:00
Raphaël Jakse 90d0dd85f4 set input type=number when relevent 2020-07-13 15:53:45 +02:00
Laurent Mazet 62edfe07e1 correct errors reported by eslint 2020-07-04 15:41:23 +02:00
Laurent Mazet e418ca7a12 remove last arrow function 2020-07-04 14:56:11 +02:00
Laurent Mazet aa2d1776ee correct highlighting when one puts a tile and create same word horizontally and vertically 2020-07-04 14:53:35 +02:00
Laurent Mazet ad0699681d correct highlighting removing for moved and moving tiles 2020-07-04 10:59:32 +02:00
Laurent Mazet 3395d5f9a5 correct spell checker button states 2020-07-04 09:02:39 +02:00
Laurent Mazet 331f0541e1 fix highlight removing when a tile is moved 2020-06-28 16:34:58 +02:00
Laurent Mazet 0fa6efb69a correct in row checking 2020-06-28 16:21:26 +02:00
Laurent Mazet e3a8b3c032 correct badWords list and simplify word list trimming 2020-06-20 23:35:45 +02:00
Laurent Mazet f607bf64e1 highlight in green or red checked words 2020-06-20 00:32:18 +02:00
Laurent Mazet 838f19ca5d add commas between words 2020-06-19 23:11:41 +02:00
Laurent Mazet 5ade05f9f4 take into account of blank tile 2020-06-19 23:10:29 +02:00
Laurent Mazet 4a541f05ee error on Hebrew dictionary and limit dictionary to 50MB (uncompressed) 2020-06-18 22:55:12 +02:00
Laurent Mazet b523d7361b add Arabian dictionary 2020-06-18 22:12:47 +02:00
Laurent Mazet ef17359dfd add Slovenian dictionary 2020-06-17 22:33:52 +02:00
Laurent Mazet a4f382eaca add Slovak dictionary 2020-06-17 21:50:36 +02:00
Laurent Mazet 0245c05f36 add Russian dictionary 2020-06-17 12:24:53 +02:00
Laurent Mazet 393eebbf1f add Czech dictionary 2020-06-17 12:06:09 +02:00
Laurent Mazet 2b6b45079d add Romanian dictionary 2020-06-16 23:44:52 +02:00
Laurent Mazet d8900365fd add Latvian dictionary 2020-06-16 23:33:46 +02:00
Laurent Mazet 438ab55974 add Icelandish dictionary 2020-06-16 22:49:46 +02:00
Laurent Mazet 958218c7f4 add Armenian dictionary 2020-06-16 22:37:40 +02:00
Laurent Mazet db8588581d error on Hungarian dictionary 2020-06-16 11:25:49 +02:00
Laurent Mazet 37f61d2bf7 add Croatian dictionary 2020-06-16 00:13:06 +02:00
Laurent Mazet 7e69ea58d3 add Galician dictionary 2020-06-15 23:41:04 +02:00
Laurent Mazet 70f535384e add Finnish dictionary 2020-06-15 23:29:06 +02:00
Laurent Mazet 3cbcda3811 correct Esperanto dictionary 2020-06-15 23:02:12 +02:00
Laurent Mazet 31a99c0cf4 add Estonian dictionary 2020-06-15 22:34:31 +02:00
Laurent Mazet fca0119e9f add Greek dictionary 2020-06-15 22:19:44 +02:00
Laurent Mazet e2581d1355 add Welsh dictionary 2020-06-15 12:00:49 +02:00
Laurent Mazet 9fd9dd913d add Breton dictionary and correct dictionary checker 2020-06-15 08:06:12 +02:00
Laurent Mazet 63629ce7e0 update git ignore list 2020-06-14 16:28:46 +02:00
Laurent Mazet edf7492ebd use dictionaries from Aspell website 2020-06-14 16:26:24 +02:00
Laurent Mazet 1595b60145 add a button to enable spell checker 2020-06-10 23:58:36 +02:00
Laurent Mazet 34dac8a414 cleaner static variable in downloadDictionary function 2020-06-10 23:01:37 +02:00
Laurent Mazet 2e40a8692e correct a spelling 2020-06-10 22:24:07 +02:00
Laurent Mazet f48df993ac handle dictionary loading error 2020-06-10 22:22:48 +02:00
Laurent Mazet aef044cdb1 change alert messages to chat messages for spelling cheker 2020-06-10 07:43:45 +02:00
Laurent Mazet 2553449b83 add an alert message when no new word found 2020-06-10 07:33:56 +02:00
Laurent Mazet 07a2b081ef update git ignore list 2020-06-09 22:43:08 +02:00
Laurent Mazet bafd01546d change dictionary format
build dictionary from aspell debian package
2020-06-09 22:27:47 +02:00
Laurent Mazet 42c7e60e2b add a rule to expand aspell dictionaries 2020-06-09 22:26:27 +02:00
Laurent Mazet 2c5ebb15d2 correct some eslint issues 2020-06-09 22:26:07 +02:00
Laurent Mazet a604b42dea correct spelling :-( 2020-06-09 22:25:56 +02:00
Laurent Mazet 1b960731ac add an alert message when all words are correct and fix a bug in the checker function 2020-06-09 22:24:55 +02:00
Laurent Mazet f29b7fc2c4 add French translations for spell checker 2020-06-09 22:24:42 +02:00
Laurent Mazet 0fffdf3788 load dictionnary for new players 2020-06-09 22:24:28 +02:00
Laurent Mazet c26ad3676e wrong name for Spanish dictionnary 2020-06-09 22:24:14 +02:00
Laurent Mazet 32a0bfe976 spell checker for multiplayer game corrected 2020-06-08 07:48:36 +02:00
Laurent Mazet 064b82478d update dictionnary building rules 2020-06-08 07:48:24 +02:00
Laurent Mazet 659db535e0 remove some city name 2020-06-08 07:47:16 +02:00
Laurent Mazet 67982da4c1 keep rule to generate dictionnaries 2020-06-08 07:35:25 +02:00
Laurent Mazet aa4301cfc9 change style for disabled buttons 2020-06-08 07:34:53 +02:00
Laurent Mazet 36f3838192 Change button state depending of dictionnary avability 2020-06-08 07:34:42 +02:00
Laurent Mazet 3b3f5e4f4c check spelling function proof of concept 2020-06-08 07:34:23 +02:00
Laurent Mazet b496e56666 add English dictionnary 2020-06-07 22:33:46 +02:00
Laurent Mazet 4f69ec084d initial spell checker 2020-06-07 22:31:17 +02:00
Raphaël Jakse 65c7c9148c Ackowledge Wikipedia for the tiles 2020-06-07 17:31:05 +02:00
Raphaël Jakse 304b1638ed Remove Lettres_du_Scrabble from the repository 2020-06-07 17:20:51 +02:00
Raphaël Jakse 33ccf280c1 Merge branch 'lmazet/trivabble-multi_board' into HEAD 2020-06-07 17:20:35 +02:00
Laurent Mazet 06c6cd2854 correct po and pot files 2020-05-24 23:18:16 +02:00
Laurent Mazet cb38c22253 move extraction lang scripts into a dedicated directory 2020-05-24 21:41:31 +02:00
Laurent Mazet aac7753bd4 add some comments to explain the need of language translating after the parsing 2020-05-23 22:31:30 +02:00
Laurent Mazet c3698558aa eslint errors 2020-05-23 22:13:18 +02:00
Laurent Mazet 86c8725272 change module file to json file 2020-05-23 22:09:37 +02:00
Laurent Mazet 9be99f42a8 Apply suggestion to l10n/make_board.js 2020-05-23 19:50:36 +00:00
Laurent Mazet 221b66f641 add 35 language tiles 2020-05-18 08:32:49 +02:00
72 changed files with 6685 additions and 421 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
/server/games.backup.json
/public/config.js
/public/dict/
/public/l10n
/.vscode

View File

@ -1,18 +1,21 @@
# -*- Makefile -*-
PORT = 3000
PORT?=3000
ESLINT?=eslint
TIDY?=tidy
ifeq (, $(shell which $(firstword ${ESLINT})))
ESLINT?=npx eslint
endif
.PHONY: all help lang start-dev-server
all: lang
all: lang emptydictlist
help:
@echo make extract-lang-dists: extract the distributions per language from Wikipedia
@echo make lang: build the translation files
@echo make eslint: use ESLint to check conformance against the coding style
@echo make start-dev-server: start a development server
@ -20,10 +23,21 @@ help:
public/l10n/js/fr.js: $(wildcard l10n/po/*/*.po)
cd l10n; make
extract-lang-dists:
cd lang-dists-extractor; make
lang: public/l10n/js/fr.js
emptydictlist: public/dict/list.js
public/dict/list.js:
mkdir -p public/dict/ && touch public/dict/list.js
eslint:
-${ESLINT} **/*.js
tidy:
-${TIDY} -xml -errors -q public/*.html
start-dev-server: lang
cd server && make start-dev-server

138
README.md
View File

@ -9,7 +9,7 @@ It features:
- a board, a bag full of tiles, a rack for every player
- a chat so people can communicate
- a way to set the score of each player
- support for different languages (set of tiles as well as the interface)
- support for different languages (set of tiles as well as the interface). Thanks to Wikipedia for providing data about tiles for each language (https://fr.wikipedia.org/wiki/Lettres_du_Scrabble)
Trivabble does not implement any rule: you are free to play your way.
It does not understand what you do and is not able to compute the score, like your real board game.
@ -24,7 +24,7 @@ It supports:
It should work on any browser released after 2015, though we haven't tested it on Internet Explorer.
This documentation is intented for people who want to install Trivabble on their server.
If you just want to play, head to https://trivabble.1s.fr/.
If you just want to play, head to https://trivabble.org/.
For contributions, see (contributing)[CONTRIBUTING.md].
@ -137,7 +137,22 @@ We will assume www-data is the UNIX user of your Web server. Adapt if necessary.
8. Configure your web server.
On Apache 2, the relevant rules are:
#### Content-Security Policy Header
Trivabble loads 5 static javascript files, 2 static css files and a sound from its origin, and connects to the same server by SSE or websockets.
Here is the recommended HTTP CSP header for Trivabble:
```
Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; connect-src 'self'; media-src 'self'
```
We advise you to set this up to improve the security of your setup.
In the next two sections, we describe the configuration for Apache 2 and Nginx.
#### Apache 2
On Apache 2, the relevant rules are:
RewriteEngine on
RewriteRule "^/?:trivabble/ws/(.*)" ws://localhost:3000/ws/$1 [P]
@ -153,7 +168,120 @@ a2enmod proxy_wstunnel
a2enmod rewrite
```
A full example is available in (doc/trivabble-apache-host.conf.sample)[doc/trivabble-apache-host.conf.sample].
:warning: Be careful to allow enough concurrent processes / threads / workers on your web server.
Each player requires one long-standing connection (XHR, SSE or WebSocket), plus small requests when not using WebSockets.
Long-standing connections may cause issues with Apache 2, and using HTTP 2 may lead to "interesting" behavior.
### Nginx
Here is an example of an Nginx configuration for Trivabble:
```
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name trivabble.example.org;
location /:trivabble/ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
location /:trivabble {
proxy_pass http://127.0.0.1:3000;
proxy_buffering off;
}
location /trivabble {
alias /var/www/html/trivabble-public;
}
# SSL configuration here
}
```
## Enable the spell checker
The process of building the dictionaries takes a lot of disk space and require huge amount of memory (around 1GB).
Install `wget` and `aspell` (to have the `word-list-compress` command), and run:
```sh
cd dict-dists-extractor
make
```
If you want to limit spelling to a subset of languages, you can define the list by the `LANGS` variable before executing the `make` command such as:
```sh
cd dict-dists-extractor
LANGS="de en fr" make
```
This way, you only build English, French and German dictionaries.
To deactivate spell checker at system level, you need to empty dictionary list contained into file `public/dict/list.js`. Such command can be used:
```sh
echo > public/dict/list.js
```
## Technical appendices
### Board extractor
Wikipedia provides tile distributions (content of the bag and points) for various languages. Board languages are built from a Wikipedia page.
#### General parsing
Most board languages are extracted from the French version of the Wikipedia page which has a simple document structure. Parsing is done by a JS script named `make_board.js`:
- each new language board is proceeded by a level 2 header containing language name,
- tile points is followed by `point(s)`
- tile letter and number of tiles are easy extracted by a regex which looks like `<b>(letter)</b> <small>x(times)</small>`
#### Special languages
Some languages are only defined into the English version. So we copy them into separated text files and parsing is done by an AWK named `make_board.awk`.
### Dictionary building process
The spell checker in Trivabble is based on Aspell dictionaries. However, as Trivabble only uses a subset of letters (most accentuated characters have to be replaced by standard ones), we can't use Aspell engine straightforward; we need to build lists of words that only use playable characters.
#### Overall concept
In order to build dictionaries for various languages, we first need to retrieve Aspell dictionary lists. Then we retrieve the last versions of dictionaries for every languages and we build them. Thanks to two Aspell commands, we build the full list of words. Based on the distribution of tiles, we translate every derived (most of the time accentuated) character by the appropriate one, and finally we remove duplicated entries.
#### Details on Makefile rules
Rule '$(OBJ_DIR)/src.mk' retrieves on Aspell site the last version of the dictionary list, extract dictionary archive URL and build a sub-makefile with rules to retrieve every needed dictionary.
Rule '%.dir' unpacks dictionary archives and build Aspell dictionary. Result directory is rename as LANG.dir
Rule '%.low' expands a Aspell dictionary into a list of words (low means "List Of Words"". Phrases are split into words. Finally the list is ordered and clean from duplicated words.
Rule '$(ROOT_DICT)/%.dict':
- excludes words with numbers, dashes, apostrophes and other forbidden signs,
- translates accentuated characters into standard ones,
- up-case all words,
- and remove duplicated words.
This file can be used by Trivabble for spell checking.
Last rule 'check-%' checks that file %.dict contains only words with characters base on language tile bag.
#### Remarks
Some lists of words are too huge (for example Hungarian or Turkish are agglutinative languages), so Trivabble will not be able to check spelling for those languages.
Some languages don't have any Aspell dictionary.
### Credits
Thanks [Laurent Mazet](http://www.softndesign.org/~mazet/) for many contributions.
Thanks [Ysabeau](https://linuxfr.org/users/ysabeau/) for the design of the bag.
Thanks every other past and future contributors who have written code, tickets,
tested the game and who I have not mentionned here yet (please tell me if your
name is missing!).

1
dict-dists-extractor/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/obj

View File

@ -0,0 +1,608 @@
# -*- Makefile -*-
ROOT_DICT = ../public/dict
OBJ_DIR = obj
# 0MB < dictionary size < 10MB
SMALL = br ca cy da de en es fr ga hr hy is lv nl no pt sv
# 10MB < Dictionary size < 50MB
LARGE = bg el eo it pl ro ru sk sl uk
# 50MB < dictionary size < 500MB
VERY_LARGE = ar cs et fi
LANGS ?= $(SMALL) $(LARGE)
DICT_RULE_PRELUDE = sortuniq() { cat > "$$1"; sort -u -o "$$1" "$$1"; }; \
echo Building $@ from $<
# he and hu: can not be generated
# af eu la ms tr xk: no aspell dictionary
ASPDICT = https://ftp.gnu.org/gnu/aspell/dict/0index.html
LOWS = $(addsuffix .low,$(LANGS))
DICTS = $(addsuffix .dict,$(LANGS))
#DEPEND = Makefile
#MAKEFLAGS = -s
.PHONY: all required count clean low list
all: required
make $(addprefix check-,$(LANGS))
make list
$(ROOT_DICT):
mkdir $(ROOT_DICT)
$(OBJ_DIR):
mkdir $(OBJ_DIR)
count:
wc -l $(ROOT_DICT)/*
low: $(LOWS)
required: ${OBJ_DIR} ${OBJ_DIR}/src.mk ${ROOT_DICT}
list: $(ROOT_DICT)/list.js
$(ROOT_DICT)/list.js: $(wildcard $(ROOT_DICT)/*.dict)
ls -s ${ROOT_DICT}/*.dict| \
awk 'BEGIN { printf "window.DictionaryList = {\n" } \
{ $$0 = gensub(/(.+) .*\/(.+)\.dict/, "\\1 \\2", "g"); \
printf "\"%s\": %d,\n", $$2, $$1 } \
END { printf "\"none\": 0\n};" }' > $@
$(OBJ_DIR)/src.mk:
echo Creation language table
wget $(ASPDICT) -q -O - | \
awk 'BEGIN { base="'`dirname $(ASPDICT)`'" } \
/<tr><td><a/ { $$0 = gensub(/.*"(.+)".*"(.+)\/(.+)".*/, "\\1 \\2 \\3", "g"); \
printf "${OBJ_DIR}/%s.dir: $(OBJ_DIR)/%s\n\n", $$1, $$3; \
printf "${OBJ_DIR}/%s:\n", $$3; \
printf "\techo Downloading %s dictionary source\n", $$1; \
printf "\twget -q %s/%s/%s -O $$@\n\n", base, $$2, $$3 } \
/<\/table>/ { exit }' > $@
include $(wildcard ${OBJ_DIR}/src.mk)
%.dir:
echo Installing $@ dictionary
cd "$$(dirname "$@")" && \
tar -xjf "$$(basename "$<")" && \
cd "$$(basename "$(<:.tar.bz2=)")" && \
./configure && \
make && \
cd .. && \
mv "$$(basename "$<" .tar.bz2)" "$$(basename "$@")"
%.low: %.dir
@echo "Building list of word $@"
export DICT_NAME="$$(basename "$<" ".dir")"; \
aspell --dict-dir="$$(realpath $<)" -d "$$DICT_NAME" dump master "$$DICT_NAME" | \
aspell --dict-dir="$$(realpath $<)" -l "$$DICT_NAME" expand | \
tr -s '[:space:]' '\n' > "$@~" && \
LC_ALL=C sort -S28G -u -o "$@~" "$@~" && \
mv "$@~" "$@"
$(OBJ_DIR)/no.low:
make $(OBJ_DIR)/nb.low
mv $(OBJ_DIR)/nb.low $@
$(OBJ_DIR)/pt.low:
make $(OBJ_DIR)/pt_PT.low
mv $(OBJ_DIR)/pt_PT.low $@
$(ROOT_DICT)/ar.dict: $(OBJ_DIR)/ar.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/[ﺏِ ]/ب/g' \
-e 's/[ﻍُ]/غ/g' \
-e 's/[ﻙ ]/ل/g' \
-e 's/[ﻡَ]/م/g' \
-e 's/[ﻥَ]/ن/g' \
-e 's/[ﻱَﻳّ]/ي/g' | \
sortuniq "$@"
# ا ل ن ش ا ش ي بِ ي ي ب ا ل ن ش ا ش ي بِ ي ي ب ن ش ا ش ي بِ ي ي ف ا ل ن ش ا ش ي بِ ي ي ف ب ا ل ن ش ا ش ي بِ ي ي ف ب ن ش ا ش ي بِ ي ي ف ك ا ل ن ش ا ش ي بِ ي ي ف ك ن ش ا ش ي بِ ي ي ف ل ل ن ش ا ش ي بِ ي ي ف ل ن ش ا ش ي بِ ي ي ف ن ش ا ش ي بِ ي ي ك ا ل ن ش ا ش ي بِ ي ي ك ن ش ا ش ي بِ ي ي ل ل ن ش ا ش ي بِ ي ي ل ن ش ا ش ي بِ ي ي ن ش ا ش ي بِ ي ي و ا ل ن ش ا ش ي بِ ي ي و ب ا ل ن ش ا ش ي بِ ي ي و ب ن ش ا ش ي بِ ي ي و ك ا ل ن ش ا ش ي بِ ي ي و ك ن ش ا ش ي بِ ي ي و ل ل ن ش ا ش ي بِ ي ي و ل ن ش ا ش ي بِ ي ي و ن ش ا ش ي بِ ي ي
$(ROOT_DICT)/bg.dict: $(OBJ_DIR)/bg.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
grep -v "^[a-zA-Z]" | \
tr '[абвгдежзийклмнопрстуфхцчшщъьюя]' '[АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ]' | \
sortuniq "$@"
$(ROOT_DICT)/br.dict: $(OBJ_DIR)/br.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[-]" | \
grep -v "[^c]'" | \
grep -v "'[^h]" | \
sed -e 's/[àâ]/a/g' \
-e 's/[éêè]/e/g' \
-e 's/[î]/i/g' \
-e 's/[ñ]/n/g' \
-e 's/[ô]/o/g' \
-e 's/[ûüù]/u/g' | \
tr '[abcdefghijklmnopqrstuvwxyz]' '[ABCDEFGHIJKLMNOPQRSTUVWXYZ]' | \
sortuniq "$@"
$(ROOT_DICT)/ca.dict: $(OBJ_DIR)/ca.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'-]" | \
sed -e 's/[áàãÁÀ]/a/g' \
-e 's/[éèÉÈ]/e/g' \
-e 's/[çÇ]/c/g' \
-e 's/[íïÍ]/i/g' \
-e 's/[ñ]/n/g' \
-e 's/[óöòÓÒ]/o/g' \
-e 's/[úüùÚ]/u/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/cs.dict: $(OBJ_DIR)/cs.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/[äâ]/a/g' \
-e 's/[çćĆ]/c/g' \
-e 's/[ęë]/e/g' \
-e 's/[î]/i/g' \
-e 's/[ľĽłĺ]/l/g' \
-e 's/[ń]/n/g' \
-e 's/[őöŐÖô]/o/g' \
-e 's/[śŚ]/s/g' \
-e 's/[űüŰÜ]/u/g' \
-e 's/[ź]/z/g' | \
sed -e 's/á/Á/g' -e 's/č/Č/g' -e 's/ď/Ď/g' -e 's/é/É/g' -e 's/ě/Ě/g' \
-e 's/í/Í/g' -e 's/ň/Ň/g' -e 's/ó/Ó/g' -e 's/ř/Ř/g' -e 's/š/Š/g' \
-e 's/ť/Ť/g' -e 's/ú/Ú/g' -e 's/ů/Ů/g' -e 's/ý/Ý/g' -e 's/ž/Ž/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/cy.dict: $(OBJ_DIR)/cy.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
grep -vi "ph" | \
sed -e 's/[âä]/a/g' \
-e 's/[êë]/e/g' \
-e 's/[îï]/i/g' \
-e 's/[ôöò]/o/g' \
-e 's/[ûüù]/u/g' \
-e 's/[ŵ]/w/g' \
-e 's/[ŷ]/y/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/da.dict: $(OBJ_DIR)/da.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'-]" | \
sed -e 's/[áä]/a/g' \
-e 's/[ð]/d/g' \
-e 's/[éëè]/e/g' \
-e 's/[íì]/i/g' \
-e 's/[óöô]/o/g' \
-e 's/[ü]/u/g' | \
tr '[a-zæøå]' '[A-ZÆØÅ]' | \
sortuniq "$@"
$(ROOT_DICT)/de.dict: $(OBJ_DIR)/de.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'-]" | \
sed -e 's/[âà]/a/g' \
-e 's/[éê]/e/g' \
-e 's/[ñ]/n/g' \
-e 's/[œ]/oe/g' \
-e 's/[ß]/ss/g' | \
tr '[a-zäöü]' '[A-ZÄÖÜ]' | \
sortuniq "$@"
$(ROOT_DICT)/el.dict: $(OBJ_DIR)/el.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/[άΆ]/α/g' \
-e 's/[ϐ]/β/g' \
-e 's/[έΈ]/ε/g' \
-e 's/[ήΉ]/η/g' \
-e 's/[ίϊΐΊ]/ι/g' \
-e 's/[όΌ]/ο/g' \
-e 's/[ς]/σ/g' \
-e 's/[ΰϋύΎ]/υ/g' \
-e 's/[ϕ]/φ/g' \
-e 's/[ώΏ]/ω/g' | \
tr '[αβγδεζηθικλμνξοπρστυφχψω]' '[ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ]' | \
sortuniq "$@"
$(ROOT_DICT)/en.dict: $(OBJ_DIR)/en.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'-]" | \
sed -e 's/[áâàäåÅ]/a/g' \
-e 's/[ç]/c/g' \
-e 's/[éêèë]/e/g' \
-e 's/[íîï]/i/g' \
-e 's/[ñ]/n/g' \
-e 's/[óôöøiÖ]/o/g' \
-e 's/[úûüùiÜ]/u/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/eo.dict: $(OBJ_DIR)/eo.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'qQwWxXyY-]" | \
tr '[a-zĉĝĥĵŝŭ]' '[A-ZĈĜĤĴŜŬ]' | \
sortuniq "$@"
$(ROOT_DICT)/es.dict: $(OBJ_DIR)/es.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'-]" | \
sed -e 's/[áÁ]/a/g' \
-e 's/[é]/e/g' \
-e 's/[í]/i/g' \
-e 's/[ó]/o/g' \
-e 's/[úü]/u/g' | \
tr '[a-zñ]' '[A-ZÑ]' | \
sortuniq "$@"
$(ROOT_DICT)/et.dict: $(OBJ_DIR)/et.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'qwxQWX-]" | \
tr '[a-zäöõüšž]' '[A-ZÄÖÕÜŠŽ]' | \
sortuniq "$@"
$(ROOT_DICT)/fi.dict: $(OBJ_DIR)/fi.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.':-]" | \
tr '[a-zäåöšž]' '[A-ZÄÅÖŠŽ]' | \
sortuniq "$@"
$(ROOT_DICT)/fr.dict: $(OBJ_DIR)/fr.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'-]" | \
sed -e 's/[àâä]/a/g' \
-e 's/[ç]/c/g' \
-e 's/[Ééèêë]/e/g' \
-e 's/[ïî]/i/g' \
-e 's/[ôö]/o/g' \
-e 's/[úùûü]/u/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/ga.dict: $(OBJ_DIR)/ga.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.':-]" | \
sed -e 's/[áâãÁ]/a/g' \
-e 's/[ç]/c/g' \
-e 's/[éèÉ]/e/g' \
-e 's/[íÍ]/i/g' \
-e 's/[óöòÓ]/o/g' \
-e 's/[úüÚ]/u/g' | \
tr '[a-zñ]' '[A-ZÑ]' | \
sortuniq "$@"
$(ROOT_DICT)/he.dict: $(OBJ_DIR)/he.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sortuniq "$@"
$(ROOT_DICT)/hr.dict: $(OBJ_DIR)/hr.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
tr '[a-zćčšž]' '[A-ZĆČŠŽ]' | \
sed 's/đ/Đ/g' | \
sortuniq "$@"
$(ROOT_DICT)/hu.dict: $(OBJ_DIR)/hu.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
tr '[a-záéóöőúüű]' '[A-ZÁÉÓÖŐÚÜŰ]' | \
sortuniq "$@"
#grep -v "['ԁԃԂԃ-]"
$(ROOT_DICT)/hy.dict: $(OBJ_DIR)/hy.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
sed -e 's/ա/Ա/g' -e 's/բ/Բ/g' -e 's/գ/Գ/g' -e 's/դ/Դ/g' -e 's/ե/Ե/g' \
-e 's/զ/Զ/g' -e 's/է/Է/g' -e 's/ը/Ը/g' -e 's/թ/Թ/g' -e 's/ժ/Ժ/g' \
-e 's/ի/Ի/g' -e 's/լ/Լ/g' -e 's/խ/Խ/g' -e 's/ծ/Ծ/g' -e 's/կ/Կ/g' \
-e 's/հ/Հ/g' -e 's/ձ/Ձ/g' -e 's/ղ/Ղ/g' -e 's/ճ/Ճ/g' -e 's/մ/Մ/g' \
-e 's/յ/Յ/g' -e 's/ն/Ն/g' -e 's/շ/Շ/g' -e 's/ո/Ո/g' -e 's/չ/Չ/g' \
-e 's/պ/Պ/g' -e 's/ջ/Ջ/g' -e 's/ռ/Ռ/g' -e 's/ս/Ս/g' -e 's/վ/Վ/g' \
-e 's/տ/Տ/g' -e 's/ր/Ր/g' -e 's/ց/Ց/g' -e 's/ւ/Ւ/g' -e 's/փ/Փ/g' \
-e 's/ք/Ք/g' -e 's/օ/Օ/g' -e 's/ֆ/Ֆ/g' -e 's/ու/ՈՒ/g' \
-e "s/'//g" | \
sortuniq "$@"
$(ROOT_DICT)/it.dict: $(OBJ_DIR)/it.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'-]" | \
sed -e 's/[àâ]/a/g' \
-e 's/[ç]/c/g' \
-e 's/[éè]/e/g' \
-e 's/[ì]/i/g' \
-e 's/[òiô]/o/g' \
-e 's/[ù]/u/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/is.dict: $(OBJ_DIR)/is.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'-]" | \
tr '[a-záæðéíóöúýþ]' '[A-ZÁÆÐÉÍÓÖÚÝÞ]' | sortuniq "$@"
$(ROOT_DICT)/lv.dict: $(OBJ_DIR)/lv.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'-]" | \
tr '[a-zāčēģīķļņšūž]' '[A-ZĀČĒĢĪĶĻŅŠŪŽ]' | sortuniq "$@"
$(ROOT_DICT)/nl.dict: $(OBJ_DIR)/nl.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[1-9+/' .-]" | \
sed -e 's/[áäâàÅ]/a/g' \
-e 's/[ç]/c/g' \
-e 's/[éëèê]/e/g' \
-e 's/[íïî]/i/g' \
-e 's/[ñ]/n/g' \
-e 's/[óöô]/o/g' \
-e 's/[úüûùÜ]/u/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/no.dict: $(OBJ_DIR)/no.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[.'\"-]" | \
sed -e 's/[áäÄ]/a/g' \
-e 's/[ç]/c/g' \
-e 's/[ð]/d/g' \
-e 's/[éëèêÉ]/e/g' \
-e 's/[íì]/i/g' \
-e 's/[óöôò]/o/g' \
-e 's/[ü]/u/g' | \
tr '[a-zæøå]' '[A-ZÆØÅ]' | \
sortuniq "$@"
$(ROOT_DICT)/pl.dict: $(OBJ_DIR)/pl.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/[ä]/a/g' \
-e 's/[ç]/c/g' \
-e 's/[é]/e/g' \
-e 's/[i]/i/g' \
-e 's/[ö]/o/g' \
-e 's/[šŠ]/s/g' \
-e 's/[û]/u/g' | \
tr '[a-złąęóśżćńź]' '[A-ZŁĄĘÓŚŻĆŃŹ]' | \
sortuniq "$@"
$(ROOT_DICT)/pt.dict: $(OBJ_DIR)/pt.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/[áãâàÁÂ]/a/g' \
-e 's/[éêèÉ]/e/g' \
-e 's/[íîÍ]/i/g' \
-e 's/[óôõÓ]/o/g' \
-e 's/[úüÚ]/u/g' | \
tr '[a-zç]' '[A-ZÇ]' | \
sortuniq "$@"
$(ROOT_DICT)/ro.dict: $(OBJ_DIR)/ro.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/[áâăÂĂ]/a/g' \
-e 's/[éè]/e/g' \
-e 's/[íîÎ]/i/g' \
-e 's/[șȘ]/s/g' \
-e 's/[țȚ]/t/g' \
-e 's/[ü]/u/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/ru.dict: $(OBJ_DIR)/ru.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/а/А/g' -e 's/б/Б/g' -e 's/в/В/g' -e 's/г/Г/g' -e 's/д/Д/g' \
-e 's/е/Е/g' -e 's/ё/Ё/g' -e 's/ж/Ж/g' -e 's/з/З/g' -e 's/и/И/g' \
-e 's/й/Й/g' -e 's/к/К/g' -e 's/л/Л/g' -e 's/м/М/g' -e 's/н/Н/g' \
-e 's/о/О/g' -e 's/п/П/g' -e 's/р/Р/g' -e 's/с/С/g' -e 's/т/Т/g' \
-e 's/у/У/g' -e 's/ф/Ф/g' -e 's/х/Х/g' -e 's/ц/Ц/g' -e 's/ч/Ч/g' \
-e 's/ш/Ш/g' -e 's/щ/Щ/g' -e 's/ъ/Ъ/g' -e 's/ы/Ы/g' -e 's/ь/Ь/g' \
-e 's/э/Э/g' -e 's/ю/Ю/g' -e 's/я/Я/g' | \
sortuniq "$@"
$(ROOT_DICT)/sk.dict: $(OBJ_DIR)/sk.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/[ë]/e/g' | \
sed -e 's/á/Á/g' -e 's/ä/Ä/g' -e 's/č/Č/g' -e 's/ď/Ď/g' -e 's/é/É/g' \
-e 's/ě/Ě/g' -e 's/í/Í/g' -e 's/ľ/Ľ/g' -e 's/ĺ/Ĺ/g' -e 's/ň/Ň/g' \
-e 's/ô/Ô/g' -e 's/ó/Ó/g' -e 's/ö/Ö/g' -e 's/ŕ/Ŕ/g' -e 's/ř/Ř/g' \
-e 's/š/Š/g' -e 's/ť/Ť/g' -e 's/ú/Ú/g' -e 's/ü/Ü/g' -e 's/ý/Ý/g' \
-e 's/ž/Ž/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/sl.dict: $(OBJ_DIR)/sl.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/[áâȁ]/a/g' \
-e 's/[ćĆ]/c/g' \
-e 's/[éȇȅ]/e/g' \
-e 's/[đĐ]/d/g' \
-e 's/[íȋȉ]/i/g' \
-e 's/[óȏȍö]/o/g' \
-e 's/[ŕȓ]/r/g' \
-e 's/[úȗȕü]/u/g' | \
sed -e 's/č/Č/g' -e 's/š/Š/g' -e 's/ž/Ž/g' | \
tr '[a-z]' '[A-Z]' | \
sortuniq "$@"
$(ROOT_DICT)/sv.dict: $(OBJ_DIR)/sv.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "['-]" | \
sed -e 's/[æ]/ae/g' \
-e 's/[ç]/c/g' \
-e 's/[é]/e/g' \
-e 's/[ü]/u/g' | \
tr '[a-zåäö]' '[A-ZÅÄÖ]' | \
sortuniq "$@"
$(ROOT_DICT)/uk.dict: $(OBJ_DIR)/uk.low $(DEPEND)
@$(DICT_RULE_PRELUDE); \
cat "$<" | \
grep -v '^.$$' | \
grep -v "[-]" | \
tr '[абвгґдеєжзиіїйклмнопрстуфхцчшщьюя]' '[АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ]' | \
sortuniq "$@"
CHECKER = cat $(1) | \
grep -v "^[$(2)]*$$" | egrep -v "$(3)" && exit 1 || echo "$< is correct"
check-ar:$(ROOT_DICT)/ar.dict
$(call CHECKER,$<,ابتثجحخدذرزسشصضطظعغفقكلمنهويءأإؤئآةى,~)
check-bg:$(ROOT_DICT)/bg.dict
$(call CHECKER,$<,АОЕИТНПРСВМБДКЛГЪЖЗУЧЯЙХЦШЮФЩЬ,~)
check-br:$(ROOT_DICT)/br.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPRSTUVWXYZ,C'H[A-Z]*(C'H)*)
check-ca:$(ROOT_DICT)/ca.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZ,L·L[A-Z]*(L·L)*)
check-cs:$(ROOT_DICT)/cs.dict
$(call CHECKER,$<,AÁBCČDĎEÉĚFGHIÍJKLMNŇOÓPQRŘSŠTŤUÚŮVWXYÝZŽ,~)
check-da:$(ROOT_DICT)/da.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ,~)
check-de:$(ROOT_DICT)/de.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ,~)
check-el:$(ROOT_DICT)/el.dict
$(call CHECKER,$<,ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ,~)
check-eo:$(ROOT_DICT)/eo.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPRSTUVZĈĜĤĴŜŬ,~)
check-es:$(ROOT_DICT)/es.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÑ,~)
check-et:$(ROOT_DICT)/et.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPRSTUVYZÄÖÕÜŠŽ,~)
check-fi:$(ROOT_DICT)/fi.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÄÅÖŠŽ,~)
check-ga:$(ROOT_DICT)/ga.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÑ,~)
check-he:$(ROOT_DICT)/he.dict
$(call CHECKER,$<,אבגדהוזחטיכלמנסעפצקרשת,~)
check-hr:$(ROOT_DICT)/hr.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZĆČĐŠŽ,~)
check-hu:$(ROOT_DICT)/hu.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÁÉÓÖŐÚÜŰ,~)
check-hy:$(ROOT_DICT)/hy.dict
$(call CHECKER,$<,ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖՈՒև,~)
check-is:$(ROOT_DICT)/is.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÁÆÐÉÍÓÖÚÝÞ,~)
check-lv:$(ROOT_DICT)/lv.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZĀČĒĢĪĶĻŅŠŪŽ,~)
check-no:$(ROOT_DICT)/no.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ,~)
check-pl:$(ROOT_DICT)/pl.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZŁĄĘÓŚŻĆŃŹ,~)
check-pt:$(ROOT_DICT)/pt.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÇ,~)
check-ru:$(ROOT_DICT)/ru.dict
$(call CHECKER,$<,АБВГДЕЁЖЗИЙКЛлМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ,~)
check-sk:$(ROOT_DICT)/sk.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÁÄČĎÉĚÍĽĹŇÔÓÖŔŠŤÚÜÝŽ,~)
check-sl:$(ROOT_DICT)/sl.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZČŠŽ,~)
check-sv:$(ROOT_DICT)/sv.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ,~)
check-uk:$(ROOT_DICT)/uk.dict
$(call CHECKER,$<,ОАИНВЕІТКРСДЛМУПЗЯЬБГЧХЄЇЙЖЦШЮҐФЩ',~)
check-%:$(ROOT_DICT)/%.dict
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZ,~)
clean:
rm -rf "$(OBJ_DIR)"

View File

@ -1,5 +1,10 @@
.PHONY: all
.PHONY: all lang
all:
.EXPORT_ALL_VARIABLES:
ROOT_LANG = ../public/l10n
all: lang
lang:
node makejs.js

0
l10n/po/br/board.po Normal file
View File

View File

@ -164,8 +164,8 @@ msgstr "Son ar c'hemennadenoù"
msgid "Number of tiles in the bag:"
msgstr "Niver a bezhioù er sac'h:"
msgid "Click on it to take one."
msgstr "Klikit warnañ evit kemer unan"
msgid "Click on the bag to take onei tile."
msgstr ""
msgid "Put back all the tiles in the bag"
msgstr "Adlakaat an holl pezhioù er sac'h"

121
l10n/po/fr/board.po Normal file
View File

@ -0,0 +1,121 @@
#TranslationFunction trivabble
msgid "Afrikaans"
msgstr "Afrikaans"
msgid "Arabic"
msgstr "Arabe"
msgid "Bulgarian"
msgstr "Bulgare"
msgid "Breton"
msgstr "Breton"
msgid "Catalan"
msgstr "Catalan"
msgid "Czech"
msgstr "Tchèque"
msgid "Welsh"
msgstr "Gallois"
msgid "Danish"
msgstr "Danois"
msgid "German"
msgstr "Allemand"
msgid "Greek"
msgstr "Grec"
msgid "English"
msgstr "Anglais"
msgid "Esperanto"
msgstr "Espéranto"
msgid "Spanish"
msgstr "Espagnol"
msgid "Estonian"
msgstr "Estonien"
msgid "Basque"
msgstr "Basque"
msgid "Finnish"
msgstr "Finlandais"
msgid "French"
msgstr "Français"
msgid "Irish"
msgstr "Irlandais"
msgid "Hebrew"
msgstr "Hébreu"
msgid "Croatian"
msgstr "Croate"
msgid "Hungarian"
msgstr "Hongrois"
msgid "Armenian"
msgstr "Arménien"
msgid "Icelandic"
msgstr "Islandais"
msgid "Italian"
msgstr "Italien"
msgid "Latin"
msgstr "Latin"
msgid "Lithuanian"
msgstr "Lituanien"
msgid "Latvian"
msgstr "Letton"
msgid "Malay"
msgstr "Malais"
msgid "Dutch"
msgstr "Néerlandais"
msgid "Norwegian"
msgstr "Norvégien"
msgid "Polish"
msgstr "Polonais"
msgid "Portuguese"
msgstr "Portugais"
msgid "Romanian"
msgstr "Roumain"
msgid "Russian"
msgstr "Russe"
msgid "Slovak"
msgstr "Slovaque"
msgid "Slovenian"
msgstr "Slovène"
msgid "Swedish"
msgstr "Suédois"
msgid "Turkish"
msgstr "Turc"
msgid "Ukrainian"
msgstr "Ukrainien"
msgid "Klingon"
msgstr "Klingon"

View File

@ -85,8 +85,8 @@ msgstr "Bruit des messages"
msgid "Number of tiles in the bag:"
msgstr "Nombre de pièces dans le sac :"
msgid "Click on it to take one."
msgstr "Cliquez dessus pour en prendre une."
msgid "Click on the bag to take one tile."
msgstr "Cliquez sur le sac pour prendre une pièce."
msgid "Put back all the tiles in the bag"
msgstr "Ranger toutes les pièces dans le sac"
@ -136,6 +136,12 @@ msgstr "Tour"
msgid "Who's turn? Click on the Turn button!"
msgstr "À qui le tour ? Cliquez sur le bouton Tour !"
msgid "Click on (+) to increase someone's score."
msgstr "Cliquez sur (+) pour augmenter le score de quelquun."
msgid "Show a cell to everyone by double-clicking on it."
msgstr "Montrez une case à tout le monde en double-cliquant dessus."
msgid "Show my rack to other players"
msgstr "Montrer mon jeu aux autres"
@ -158,28 +164,127 @@ msgid "Are you sure you want to change board to '{0}'? This will put all the ti
msgstr "Êtes-vous sûr·e de vouloir de changer la langue du plateau à '{0}' ? Cela remettra toutes les lettres du jeu dans le sac et commencera une nouvelle partie."
msgid "Board language:"
msgstr "Langue du plateau :"
msgstr "Langue du plateau :"
msgid "English"
msgstr "Anglais"
msgid "You changed the board to {0} for language {1}"
msgstr "Vous avez changé le plateau pour {0} en {1}"
msgid "French"
msgstr "Français"
msgid "{0} changed the board to {1} for language {2}"
msgstr "{0} a changé le plateau pour {1} en {2}"
msgid "German"
msgstr "Allemand"
msgid "Settings"
msgstr "Paramètres"
msgid "Spanish"
msgstr "Espagnol"
msgid "Check spelling for new words"
msgstr "Vérifier l'orthographe des mots nouveaux"
msgid "Romanian"
msgstr "Roumain"
msgid "Incorrect spelling for {0} from {1}"
msgstr "Orthographe incorrecte pour {0} parmi {1}"
msgid "Portuguese"
msgstr "Portuguais"
msgid "All words are correct: {0}"
msgstr "Tous les mots sont corrects : {0}"
msgid "You changed the language of the board to {0}"
msgstr "Vous avez changé la langue du plateau en {0}"
msgid "No new word found"
msgstr "Aucun nouveau mot trouvé"
msgid "{0} changed the language of the board to {1}"
msgstr "{0} a changé la langue du plateau en {1}"
msgid "Incorrect dictionary file."
msgstr "Dictionnaire incorrect."
msgid "Can't load dictionary file."
msgstr "Impossible de charger le dictionnaire"
msgid "Spell checking requires Trivabble to download a dictionary. Do you confirm?"
msgstr "La vérification orthographique nécessite que Trivabble télécharge un dictionnaire. Confirmez-vous ?"
msgid "Spell checking is based on:"
msgstr "La vérification orthographique est basée sur :"
msgid "{0} points will be added to:"
msgstr "{0} points vont être ajoutés à:"
msgid "There are no points to add."
msgstr "Il ny a pas de point à ajouter."
msgid "Settings"
msgstr "Paramètres"
msgid "Configuration window"
msgstr "Fenêtre de configuration"
msgid "Look at:"
msgstr "Regardez ici :"
msgid "Double tap duration:"
msgstr "Durée de la double tape :"
msgid "(slow)"
msgstr "(lent)"
msgid "(fast)"
msgstr "(rapide)"
msgid "Flash light duration:"
msgstr "Durée du flash laser :"
msgid "Flash light color"
msgstr "Couleur du flash laser"
msgid "Tip!"
msgstr "Astuce !"
msgid "Next tip"
msgstr "Astuce suivante"
msgid "Disable the spell checker"
msgstr "Désactiver la vérification orthographique"
msgid "Spell checking is not available for this language."
msgstr "La vérification orthographique n'est pas disponible dans cette langue."
msgid "Score new words"
msgstr "Compter les points"
msgid "Turn:"
msgstr "Tour :"
msgid "{0}d"
msgstr "{0}j"
msgid "{0}h {1}' {2}''"
msgstr "{0} h {1} min {2} s"
msgid "{0}' {1}''"
msgstr "{0} min {1}"
msgid "Show the timer"
msgstr "Chronométrer la partie"
msgid "To measure playing time, activate the timer."
msgstr "Pour mesurer les temps de jeu, activez le chronomètre."
msgid "Cell captions:"
msgstr "Légendes des cellules :"
msgid "Clip when overflow"
msgstr "Raccourcies en cas de débordement"
msgid "Dots when overflow"
msgstr "Pointillés en cas de débordement"
msgid "No caption"
msgstr "Pas de légende"
msgid "Short caption"
msgstr "Légendes courtes"
msgid "Board configuration:"
msgstr "Configuration du plateau"
msgid "Are you sure you want to change board to {0}? This will put all the tiles back in the bag and start another game."
msgstr "Êtes-vous sûr·e de vouloir de changer le type du plateau à {0} ? Cela remettra toutes les lettres du jeu dans le sac et commencera une nouvelle partie."
msgid "Can't find board '{0}'. Change board or start a new game."
msgstr "Impossible de trouver le plateau de type '{0}'. Changez de type de plateau ou démarrez une nouvelle partie."
msgid "Caution, this feature is experimental; any feedback will be appreciated"
msgstr "Attention, cette fonctionnalité est expérimentale ; tout commentaire sera grandement apprécié"

121
l10n/po/ro/board.po Normal file
View File

@ -0,0 +1,121 @@
#TranslationFunction trivabble
msgid "Afrikaans"
msgstr "afrikaans"
msgid "Arabic"
msgstr "arabic"
msgid "Bulgarian"
msgstr "bulgară"
msgid "Breton"
msgstr "breton"
msgid "Catalan"
msgstr "catalan"
msgid "Czech"
msgstr "ceh"
msgid "Welsh"
msgstr "velșă"
msgid "Danish"
msgstr "danez"
msgid "German"
msgstr "germana"
msgid "Greek"
msgstr "greacă"
msgid "English"
msgstr "engleză"
msgid "Esperanto"
msgstr "esperanto"
msgid "Spanish"
msgstr "spaniolă"
msgid "Estonian"
msgstr "eston"
msgid "Basque"
msgstr "bască"
msgid "Finnish"
msgstr "finlandeză"
msgid "French"
msgstr "franceza"
msgid "Irish"
msgstr "irlandez"
msgid "Hebrew"
msgstr "ebraică"
msgid "Croatian"
msgstr "croat"
msgid "Hungarian"
msgstr "maghiar"
msgid "Armenian"
msgstr "armean"
msgid "Icelandic"
msgstr "islandeză"
msgid "Italian"
msgstr "italiană"
msgid "Latin"
msgstr "latin"
msgid "Lithuanian"
msgstr "lituanian"
msgid "Latvian"
msgstr "letonă"
msgid "Malay"
msgstr "malaezian"
msgid "Dutch"
msgstr "olandeză"
msgid "Norwegian"
msgstr "norvegian"
msgid "Polish"
msgstr "polonez"
msgid "Portuguese"
msgstr "portugheză"
msgid "Romanian"
msgstr "română"
msgid "Russian"
msgstr "rusă"
msgid "Slovak"
msgstr "slovacă"
msgid "Slovenian"
msgstr "sloven"
msgid "Swedish"
msgstr "suedez"
msgid "Turkish"
msgstr "turc"
msgid "Ukrainian"
msgstr "ucrainean"
msgid "Klingon"
msgstr "klingoniană"

View File

@ -156,8 +156,8 @@ msgstr "Sunet de la mesaje"
msgid "Number of tiles in the bag:"
msgstr "Număr de jetoane în sac:"
msgid "Click on it to take one."
msgstr "Apasă pe el ca să iei unul."
msgid "Click on the bag to take one tile."
msgstr ""
msgid "Put back all the tiles in the bag"
msgstr "Pune toate jetoanele înapoi în sac"
@ -250,6 +250,3 @@ msgstr "{0} își arată suportul:"
msgid "You cannot take another tile: the bag is empty."
msgstr "Nu poți lua alt jeton: sacul este gol."
msgid "Romanian"
msgstr "Română"

121
l10n/pot/board.pot Normal file
View File

@ -0,0 +1,121 @@
#TranslationFunction trivabble
msgid "Afrikaans"
msgstr ""
msgid "Arabic"
msgstr ""
msgid "Bulgarian"
msgstr ""
msgid "Breton"
msgstr ""
msgid "Catalan"
msgstr ""
msgid "Czech"
msgstr ""
msgid "Welsh"
msgstr ""
msgid "Danish"
msgstr ""
msgid "German"
msgstr ""
msgid "Greek"
msgstr ""
msgid "English"
msgstr ""
msgid "Esperanto"
msgstr ""
msgid "Spanish"
msgstr ""
msgid "Estonian"
msgstr ""
msgid "Basque"
msgstr ""
msgid "Finnish"
msgstr ""
msgid "French"
msgstr ""
msgid "Irish"
msgstr ""
msgid "Hebrew"
msgstr ""
msgid "Croatian"
msgstr ""
msgid "Hungarian"
msgstr ""
msgid "Armenian"
msgstr ""
msgid "Icelandic"
msgstr ""
msgid "Italian"
msgstr ""
msgid "Latin"
msgstr ""
msgid "Lithuanian"
msgstr ""
msgid "Latvian"
msgstr ""
msgid "Malay"
msgstr ""
msgid "Dutch"
msgstr ""
msgid "Norwegian"
msgstr ""
msgid "Polish"
msgstr ""
msgid "Portuguese"
msgstr ""
msgid "Romanian"
msgstr ""
msgid "Russian"
msgstr ""
msgid "Slovak"
msgstr ""
msgid "Slovenian"
msgstr ""
msgid "Swedish"
msgstr ""
msgid "Turkish"
msgstr ""
msgid "Ukrainian"
msgstr ""
msgid "Klingon"
msgstr ""

View File

@ -87,7 +87,7 @@ msgstr ""
msgid "Number of tiles in the bag:"
msgstr ""
msgid "Click on it to take one."
msgid "Click on the bag to take one tile."
msgstr ""
msgid "Put back all the tiles in the bag"
@ -142,6 +142,12 @@ msgstr ""
msgid "Who's turn? Click on the Turn button!"
msgstr ""
msgid "Click on (+) to increase someone's score."
msgstr ""
msgid "Show a cell to everyone by double-clicking on it."
msgstr ""
msgid "Show my rack to other players"
msgstr ""
@ -166,26 +172,124 @@ msgstr ""
msgid "Board language:"
msgstr ""
msgid "English"
msgid "You changed the board to {0} for language {1}"
msgstr ""
msgid "French"
msgid "{0} changed the board to {1} for language {2}"
msgstr ""
msgid "German"
msgid "Settings"
msgstr ""
msgid "Spanish"
msgid "Check spelling for new words"
msgstr ""
msgid "Romanian"
msgid "Incorrect spelling for {0} from {1}"
msgstr ""
msgid "Portuguese"
msgid "All words are correct: {0}"
msgstr ""
msgid "You changed the language of the board to {0}"
msgid "No new word found"
msgstr ""
msgid "{0} changed the language of the board to {1}"
msgid "Incorrect dictionary file."
msgstr ""
msgid "Can't load dictionary file."
msgstr ""
msgid "Spell checking requires Trivabble to download a dictionary. Do you confirm?"
msgstr ""
msgid "Spell checking is based on:"
msgstr ""
msgid "{0} points will be added to:"
msgstr ""
msgid "There are no points to add."
msgstr: ""
msgid "Settings"
msgstr ""
msgid "Configuration window"
msgid "Look at:"
msgstr ""
msgid "Double tap duration:"
msgstr ""
msgid "(slow)"
msgstr ""
msgid "(fast)"
msgstr ""
msgid "Flash light duration:"
msgstr ""
msgid "Flash light color"
msgstr ""
msgid "Tip!"
msgstr ""
msgid "Next tip"
msgstr ""
msgid "Disable the spell checker"
msgstr ""
msgid "Spell checking is not available for this language."
msgstr ""
msgid "Score new words"
msgstr ""
msgid "Turn:"
msgstr ""
msgid "{0}d"
msgstr ""
msgid "{0}h {1}' {2}''"
msgstr ""
msgid "{0}' {1}''"
msgstr ""
msgid "Show the timer"
msgstr ""
msgid "To measure playing time, activate the timer."
msgstr ""
msgid "Cell captions:"
msgstr ""
msgid "Clip when overflow"
msgstr ""
msgid "Dots when overflow"
msgstr ""
msgid "No caption"
msgstr ""
msgid "Short caption"
msgstr ""
msgid "Board configuration:"
msgstr ""
msgid "Are you sure you want to change board to {0}? This will put all the tiles back in the bag and start another game."
msgstr ""
msgid "Can't find board '{0}'. Change board or start a new game."
msgstr ""
msgid "Caution, this feature is experimental; any feedback will be appreciated"
msgstr ""

View File

@ -0,0 +1,38 @@
.PHONY: all multiple-boards extra-boards pot-file
.EXPORT_ALL_VARIABLES:
ROOT_BOARD = ../server/lang
POT_FILE = ../l10n/pot/board.pot
EXTRA = br.json xk.json uk.json
all:
make multiple-boards
make extra-boards
make pot-file
multiple-boards: Lettres_du_Scrabble
node make_board.js
extra-boards: $(addprefix $(ROOT_BOARD)/,$(EXTRA))
$(ROOT_BOARD)/br.json: tile-Breton.txt make_board.awk Makefile
$(ROOT_BOARD)/xk.json: tile-Klingon.txt make_board.awk Makefile
$(ROOT_BOARD)/uk.json: tile-Ukrainian.txt make_board.awk Makefile
$(addprefix $(ROOT_BOARD)/,$(EXTRA)):
cat $< | awk -f make_board.awk | \
sed s/@LANG@/$(subst tile-,,$(<:.txt=))/ | \
sed s/@CODE@/$(subst $(ROOT_BOARD)/,,$(@:.json=))/ > $@
pot-file: $(POT_FILE)
$(POT_FILE): $(sort $(wildcard $(ROOT_BOARD)/*.json))
awk 'BEGIN { print "#TranslationFunction trivabble" } \
{ gsub(/[":,]/, "") } \
/name/ { printf "\nmsgid \"%s\"\nmsgstr \"\"\n", $$2 }' $^ > $@
Lettres_du_Scrabble:
wget https://fr.wikipedia.org/wiki/Lettres_du_Scrabble

View File

@ -0,0 +1,380 @@
{
"langFr": {
"aa": "Afar",
"ab": "Abkhaze",
"ae": "Avestique",
"af": "Afrikaans",
"ak": "Akan",
"am": "Amharique",
"an": "Aragonais",
"ar": "Arabe",
"as": "Assamais",
"av": "Avar",
"ay": "Aymara",
"az": "Azéri",
"ba": "Bachkir",
"be": "Biélorusse",
"bg": "Bulgare",
"bh": "Bihari",
"bi": "Bichelamar",
"bm": "Bambara",
"bn": "Bengali",
"bo": "Tibétain",
"br": "Breton",
"bs": "Bosnien",
"ca": "Catalan",
"ce": "Tchétchène",
"ch": "Chamorro",
"co": "Corse",
"cr": "Cri",
"cs": "Tchèque",
"cu": "Vieux-slave",
"cv": "Tchouvache",
"cy": "Gallois",
"da": "Danois",
"de": "Allemand",
"dv": "Maldivien",
"dz": "Dzongkha",
"ee": "Ewe",
"el": "Grec",
"en": "Anglais",
"eo": "Espéranto",
"es": "Espagnol",
"et": "Estonien",
"eu": "Basque",
"fa": "Persan",
"ff": "Peul",
"fi": "Finnois",
"fj": "Fidjien",
"fo": "Féroïen",
"fr": "Français",
"fy": "Frison occidental",
"ga": "Irlandais",
"gd": "Écossais",
"gl": "Galicien",
"gn": "Guarani",
"gu": "Gujarati",
"gv": "Mannois",
"ha": "Haoussa",
"he": "Hébreu",
"hi": "Hindi",
"ho": "Hiri motu",
"hr": "Croate",
"ht": "Créole haïtien",
"hu": "Hongrois",
"hy": "Arménien",
"hz": "Héréro",
"ia": "Interlingua",
"id": "Indonésien",
"ie": "Occidental",
"ig": "Igbo",
"ii": "Yi",
"ik": "Inupiak",
"io": "Ido",
"is": "Islandais",
"it": "Italien",
"iu": "Inuktitut",
"ja": "Japonais",
"jv": "Javanais",
"ka": "Géorgien",
"kg": "Kikongo",
"ki": "Kikuyu",
"kj": "Kuanyama",
"kk": "Kazakh",
"kl": "Groenlandais",
"km": "Khmer",
"kn": "Kannada",
"ko": "Coréen",
"kr": "Kanouri",
"ks": "Cachemiri",
"ku": "Kurde",
"kv": "Komi",
"kw": "Cornique",
"ky": "Kirghiz",
"la": "Latin",
"lb": "Luxembourgeois",
"lg": "Ganda",
"li": "Limbourgeois",
"ln": "Lingala",
"lo": "Lao",
"lt": "Lituanien",
"lu": "Luba",
"lv": "Letton",
"mg": "Malgache",
"mh": "Marshallais",
"mi": "Maori de Nouvelle-Zélande",
"mk": "Macédonien",
"ml": "Malayalam",
"mn": "Mongol",
"mo": "Moldave",
"mr": "Marathi",
"ms": "Malais",
"mt": "Maltais",
"my": "Birman",
"na": "Nauruan",
"nb": "Norvégien Bokmål",
"nd": "Sindebele",
"ne": "Népalais",
"ng": "Ndonga",
"nl": "Néerlandais",
"nn": "Norvégien Nynorsk",
"no": "Norvégien",
"nr": "Nrebele",
"nv": "Navajo",
"ny": "Chichewa",
"oc": "Occitan",
"oj": "Ojibwé",
"om": "Oromo",
"or": "Oriya",
"os": "Ossète",
"pa": "Pendjabi",
"pi": "Pali",
"pl": "Polonais",
"ps": "Pachto",
"pt": "Portugais",
"qu": "Quechua",
"rc": "Créole Réunionnais ",
"rm": "Romanche",
"rn": "Kirundi",
"ro": "Roumain",
"ru": "Russe",
"rw": "Kinyarwanda",
"sa": "Sanskrit",
"sc": "Sarde",
"sd": "Sindhi",
"se": "Same du Nord",
"sg": "Sango",
"sh": "Serbo-croate",
"si": "Cingalais",
"sk": "Slovaque",
"sl": "Slovène",
"sm": "Samoan",
"sn": "Shona",
"so": "Somali",
"sq": "Albanais",
"sr": "Serbe",
"ss": "Swati",
"st": "Sotho du Sud",
"su": "Soundanais",
"sv": "Suédois",
"sw": "Swahili",
"ta": "Tamoul",
"te": "Télougou",
"tg": "Tadjik",
"th": "Thaï",
"ti": "Tigrigna",
"tk": "Turkmène",
"tl": "Tagalog",
"tn": "Tswana",
"to": "Tongien",
"tr": "Turc",
"ts": "Tsonga",
"tt": "Tatar",
"tw": "Twi",
"ty": "Tahitien",
"ug": "Ouïghour",
"uk": "Ukrainien",
"ur": "Ourdou",
"uz": "Ouzbek",
"ve": "Venda",
"vi": "Vietnamien",
"vo": "Volapük",
"wa": "Wallon",
"wo": "Wolof",
"xh": "Xhosa",
"yi": "Yiddish",
"yo": "Yoruba",
"za": "Zhuang",
"zh": "Chinois",
"zu": "Zoulou"
},
"langEn": {
"aa": "Afar",
"ab": "Abkhazian",
"ae": "Avestan",
"af": "Afrikaans",
"ak": "Akan",
"am": "Amharic",
"an": "Aragonese",
"ar": "Arabic",
"as": "Assamese",
"av": "Avaric",
"ay": "Aymara",
"az": "Azerbaijani",
"ba": "Bashkir",
"be": "Belarusian",
"bg": "Bulgarian",
"bh": "Bihari",
"bi": "Bislama",
"bm": "Bambara",
"bn": "Bengali",
"bo": "Tibetan",
"br": "Breton",
"bs": "Bosnian",
"ca": "Catalan",
"ce": "Chechen",
"ch": "Chamorro",
"co": "Corsican",
"cr": "Cree",
"cs": "Czech",
"cu": "Old Church Slavonic",
"cv": "Chuvash",
"cy": "Welsh",
"da": "Danish",
"de": "German",
"dv": "Divehi",
"dz": "Dzongkha",
"ee": "Ewe",
"el": "Greek",
"en": "English",
"eo": "Esperanto",
"es": "Spanish",
"et": "Estonian",
"eu": "Basque",
"fa": "Persian",
"ff": "Fulah",
"fi": "Finnish",
"fj": "Fijian",
"fo": "Faroese",
"fr": "French",
"fy": "Western Frisian",
"ga": "Irish",
"gd": "Scottish Gaelic",
"gl": "Galician",
"gn": "Guarani",
"gu": "Gujarati",
"gv": "Manx",
"ha": "Hausa",
"he": "Hebrew",
"hi": "Hindi",
"ho": "Hiri Motu",
"hr": "Croatian",
"ht": "Haitian",
"hu": "Hungarian",
"hy": "Armenian",
"hz": "Herero",
"ia": "Interlingua",
"id": "Indonesian",
"ie": "Interlingue",
"ig": "Igbo",
"ii": "Sichuan Yi",
"ik": "Inupiaq",
"io": "Ido",
"is": "Icelandic",
"it": "Italian",
"iu": "Inuktitut",
"ja": "Japanese",
"jv": "Javanese",
"ka": "Georgian",
"kg": "Kongo",
"ki": "Kikuyu",
"kj": "Kwanyama",
"kk": "Kazakh",
"kl": "Greenlandic",
"km": "Khmer",
"kn": "Kannada",
"ko": "Korean",
"kr": "Kanuri",
"ks": "Kashmiri",
"ku": "Kurdish",
"kv": "Komi",
"kw": "Cornish",
"ky": "Kirghiz",
"la": "Latin",
"lb": "Luxembourgish",
"lg": "Ganda",
"li": "Limburgish",
"ln": "Lingala",
"lo": "Lao",
"lt": "Lithuanian",
"lu": "Luba",
"lv": "Latvian",
"mg": "Malagasy",
"mh": "Marshallese",
"mi": "Māori",
"mk": "Macedonian",
"ml": "Malayalam",
"mn": "Mongolian",
"mo": "Moldavian",
"mr": "Marathi",
"ms": "Malay",
"mt": "Maltese",
"my": "Burmese",
"na": "Nauru",
"nb": "Norwegian Bokmål",
"nd": "North Ndebele",
"ne": "Nepali",
"ng": "Ndonga",
"nl": "Dutch",
"nn": "Norwegian Nynorsk",
"no": "Norwegian",
"nr": "South Ndebele",
"nv": "Navajo",
"ny": "Chichewa",
"oc": "Occitan",
"oj": "Ojibwa",
"om": "Oromo",
"or": "Oriya",
"os": "Ossetian",
"pa": "Panjabi",
"pi": "Pāli ",
"pl": "Polish",
"ps": "Pashto",
"pt": "Portuguese",
"qu": "Quechua",
"rc": "Reunionese ",
"rm": "Romansh",
"rn": "Kirundi",
"ro": "Romanian",
"ru": "Russian",
"rw": "Kinyarwanda",
"sa": "Sanskrit",
"sc": "Sardinian",
"sd": "Sindhi",
"se": "Northern Sami",
"sg": "Sango",
"sh": "Serbo-Croatian ",
"si": "Sinhalese",
"sk": "Slovak",
"sl": "Slovenian",
"sm": "Samoan",
"sn": "Shona",
"so": "Somali",
"sq": "Albanian",
"sr": "Serbian",
"ss": "Swati",
"st": "Sotho",
"su": "Sundanese",
"sv": "Swedish",
"sw": "Swahili",
"ta": "Tamil",
"te": "Telugu",
"tg": "Tajik",
"th": "Thai",
"ti": "Tigrinya",
"tk": "Turkmen",
"tl": "Tagalog",
"tn": "Tswana",
"to": "Tonga",
"tr": "Turkish",
"ts": "Tsonga",
"tt": "Tatar",
"tw": "Twi",
"ty": "Tahitian",
"ug": "Uighur",
"uk": "Ukrainian",
"ur": "Urdu",
"uz": "Uzbek",
"ve": "Venda",
"vi": "Viêt Namese",
"vo": "Volapük",
"wa": "Walloon",
"wo": "Wolof",
"xh": "Xhosa",
"yi": "Yiddish",
"yo": "Yoruba",
"za": "Zhuang",
"zh": "Chinese",
"zu": "Zulu"
}
}

View File

@ -0,0 +1,40 @@
#!/usr/bin/awk -f
BEGIN {
bag = table = values = ""
}
{
table = table " " $0 "\n"
}
$1 == "-" { sub(/- /, "") }
/^[0-9]/ {
points = $1
sub(/.*:/, "")
gsub(/[×,]/, "")
for (i = 1; i<= NF; i+=2) {
lettre = $(i)
if ((lettre == "blank") || (lettre ~ /[Jj]oker/)) {
lettre = " "
}
nombre = $(i+1)
bag = bag " "
for (j = 0; j < nombre; j++) {
bag = bag " \"" lettre "\","
}
bag = bag "\n"
values = values " \"" lettre "\": " points ",\n"
}
}
END {
sub(/..$/, "\n", bag)
sub(/..$/, "\n", values)
print "{\n \"code\": \"@CODE@\",\n \"name\": \"@LANG@\",\n"
#print " /*\n" table " */\n"
print " \"bag\": [\n" bag " ],\n"
print " \"letterValues\": {\n" values " }"
print "}"
}

View File

@ -0,0 +1,105 @@
#!/usr/bin/env node
// vim: noai:ts=4:sw=4
/* eslint-disable no-multi-str */
/* eslint-disable no-process-env */
/* eslint-disable no-sync */
const ROOT = process.env.ROOT_BOARD || ".";
const fs = require("fs");
const path = require("path");
/* The French wikipedia page is easier to parse */
const htmlText = fs.readFileSync("Lettres_du_Scrabble", {encoding: "utf-8"});
/* Table used to translate language name from French to English */
const code = require(path.join(__dirname, "languageCodes.json")); // eslint-disable-line global-require
let lang;
let key;
let bag = "";
let values = "";
let nbJockers = 0;
for (const line of htmlText.split("\n")) {
/* Search language */
if (line.match(/<h2.*mw-headline/u)) {
/* Create previous language board definition */
if (bag.length > 1) {
bag = bag.slice(0, -2);
values = values.slice(0, -2) + "\n";
/* Board file */
let file = "{\n";
file += " \"code\": \"" + key + "\",\n";
file += " \"name\": \"" + lang + "\",\n";
file += "\n";
file += " \"bag\": [\n" + bag + "\n ],\n";
file += "\n";
file += " \"letterValues\": {\n";
file += values;
file += " }\n";
file += "}\n";
fs.writeFileSync(path.join(ROOT, key + ".json"), file);
}
/* Get language name */
const regexpLang = /mw-headline"[^<]*">(?<lang>[^<]*)</gu;
lang = regexpLang.exec(line).groups.lang;
/* As parsing has been done on the French page, one needs to
translate language name from French to English */
for (const k of Object.keys(code.langFr)) {
if (code.langFr[k] === lang) {
lang = code.langEn[k];
key = k;
break;
}
}
/* Empty bag */
bag = values = "";
nbJockers = 0;
}
/* Search tile */
if (line.match(/<li.*<\/li>/u) && (nbJockers < 2)) {
/* Search value */
const regexpValue = /i>(?<value>[^<]*) point/gu;
let value = regexpValue.exec(line);
if (value) {
value = value.groups.value;
}
/* Search letters */
const regexpTiles = /<b>(?<letter>[^<]*)<\/b> [^<]*<small>[×x](?<times>[^<,]*),*<\/small>/gu;
let matches;
const tiles = [];
while ((matches = regexpTiles.exec(line))) {
tiles.push(matches.groups);
}
/* Create bag and values table */
for (let i = 0; i < tiles.length; i++) {
if (tiles[i].letter.length > 2) {
tiles[i].letter = " ";
nbJockers++;
if (nbJockers === 2) {
break;
}
}
bag += " ";
for (let j = 0; j < tiles[i].times; j++) {
bag += " \"" + tiles[i].letter + "\",";
}
bag += "\n";
values += " \"" + tiles[i].letter + "\": " + value + ",\n";
}
}
}

View File

@ -0,0 +1,10 @@
Breton-language Scrabble sets, created in 2008 as Skrabell, use these 100 tiles.
- 0 point: blank ×2
- 1 point: E ×14, A ×12, N ×9, R ×7, O ×6, T ×5, U ×5, I ×4, L ×4
- 2 points: D ×4
- 3 points: G ×3, S ×3, V ×3, H ×2
- 4 points: B ×2, K ×2, M ×2, Z ×2, ZH ×2, CH ×1, C'H ×1
- 5 points: P ×1
- 10 points: F ×1, J ×1, W ×1, Y ×1
C, Q, and X are absent because they are only used in loanwords or, in the case of C, the digraphs CH and C'H. However, these letters can be played with a blank. Diacritical marks are ignored.

View File

@ -0,0 +1,12 @@
Klingon-language sets use these 100 tiles:
- 0 point: blank ×2
- 1 point: ʼ ×10, a ×10, e ×8, ɪ ×8, o ×6, u ×6, H ×5
- 2 points: j ×5, m ×5, D ×4, v ×4
- 3 points: l ×3, b ×2, ch ×2, gh ×2, n ×2, q ×2, S ×2
- 4 points: p ×2, t ×2
- 5 points: w ×2, y ×2
- 6 points: Q ×1, r ×1
- 8 points: tlh ×1
- 10 points: ng ×1
The letter tiles may show Klingon symbols (pIqaD), their renderings in the English alphabet, or both. This is not an official version of the game, although Hasbro did create their own licensed "Star Trek Scrabble" game in which players can receive bonus points by playing Klingon words. "Star Trek Scrabble" uses standard English-language tiles.

View File

@ -0,0 +1,12 @@
La version officielle du Scrabble en ukrainien a été commercialisée en 2010. Elle utilise l'alphabet cyrillique et compte 102 jetons.
- 0 point: Jokers ×2
- 1 point: О ×9, А ×8, И ×6, Н ×6, В ×5, Е ×5, І ×5, Т ×5
- 2 points: К ×4, Р ×4, С ×4
- 3 points: Д ×3, Л ×3, М ×3, У ×3
- 4 points: П ×3, З ×2, Я ×2, Ь ×2
- 5 points: Б ×2, Г ×2, Ч ×2, Х ×1
- 8 points: Є ×1, Ї ×1, Й ×1, Ж ×1, Ц ×1, Ш ×1, Ю ×1
- 10 points: Ґ ×1, Ф ×1, Щ ×1, ' ×1
Le signe d'apostrophe est également inclus, même s'il ne s'agit pas d'une lettre de l'alphabet ukrainien.

View File

@ -12,7 +12,7 @@
-webkit-justify-content:center;
justify-content:center;
line-height:1.5em;
text-align:center
text-align:center;
}
.alert-outer {
@ -31,11 +31,20 @@
padding:4px;
}
.alert-content {
padding:1ex
.alert.on-ipad.prompt {
justify-content:flex-start;
position:absolute;
}
.alert input[type=text], .alert input[type=password] {
.alert.on-ipad.prompt .alert-outer {
margin-top:1em;
}
.alert-content-and-input {
padding:1ex;
}
.alert input[type=text], .alert input[type=number], .alert input[type=password] {
border-radius:none;
box-sizing:border-box;
min-height:1.5rem;
@ -72,3 +81,18 @@
border-radius:3px
}
.alert-prompt-buttons {
display: none;
}
.alert.choice .alert-prompt-buttons, .alert.prompt .alert-prompt-buttons {
display: block;
}
.alert.choice.choice-inline .alert-content, .choice.choice-inline .alert-prompt {
display:inline-block;
}
.alert.choice.choice-inline .alert-prompt {
padding-left: 1ex;
}

View File

@ -12,6 +12,7 @@
let divAlertCallbackYes;
let divAlertCallbackNo;
let alertInput;
let alertSelect;
let divAlertContent;
const _ = (window.libD && libD.l10n) ? libD.l10n() : function (s) {
@ -22,6 +23,7 @@
divAlert.style.display = "none";
if (divAlertCallback) {
divAlertCallback(alertInput.value);
divAlertCallback = null;
}
}
@ -29,6 +31,7 @@
divAlert.style.display = "none";
if (divAlertCallback) {
divAlertCallback(null);
divAlertCallback = null;
}
}
@ -36,12 +39,15 @@
divAlert.style.display = "none";
if (divAlertCallbackYes) {
divAlertCallbackYes();
divAlertCallbackYes = null;
}
}
function confirmNo() {
divAlert.style.display = "none";
if (divAlertCallbackNo) {
divAlertCallbackNo();
divAlertCallbackNo = null;
}
}
@ -57,6 +63,11 @@
divAlert.className = "alert";
divAlert.style.display = "none";
// eslint-disable-next-line require-unicode-regexp
if ((/iPad|iPhone|iPod/g).test(navigator.userAgent)) {
divAlert.classList.add("on-ipad");
}
divAlertContent = document.createElement("div");
divAlertContent.className = "alert-content";
divAlertContent.style.whiteSpace = "pre-wrap";
@ -75,14 +86,26 @@
divAlertInput.appendChild(alertInput);
divAlertInput.appendChild(document.createElement("div"));
divAlertInput.lastChild.className = "alert-prompt-buttons";
divAlertInput.lastChild.appendChild(document.createElement("button"));
divAlertInput.lastChild.lastChild.textContent = _("OK");
divAlertInput.lastChild.lastChild.onclick = promptOK;
divAlertInput.lastChild.appendChild(document.createElement("button"));
divAlertInput.lastChild.lastChild.textContent = _("Annuler");
divAlertInput.lastChild.lastChild.onclick = promptCancel;
alertSelect = document.createElement("select");
alertSelect.onchange = function () {
alertInput.value = alertSelect.value;
};
divAlertInput.appendChild(alertSelect);
const divAlertContentAndInput = document.createElement("div");
divAlertContentAndInput.className = "alert-content-and-input";
divAlertContentAndInput.appendChild(divAlertContent);
divAlertContentAndInput.appendChild(divAlertInput);
const divAlerPromptButton = document.createElement("div");
divAlerPromptButton.className = "alert-prompt-buttons";
divAlerPromptButton.appendChild(document.createElement("button"));
divAlerPromptButton.lastChild.textContent = _("OK");
divAlerPromptButton.lastChild.onclick = promptOK;
divAlerPromptButton.appendChild(document.createElement("button"));
divAlerPromptButton.lastChild.textContent = _("Cancel");
divAlerPromptButton.lastChild.onclick = promptCancel;
divAlertConfirm = document.createElement("div");
divAlertConfirm.className = _("alert-confirm");
@ -101,12 +124,18 @@
const divAlertOuter = document.createElement("div");
divAlertOuter.className = "alert-outer";
divAlertOuter.appendChild(divAlertContent);
divAlertOuter.appendChild(divAlertInput);
divAlertOuter.appendChild(divAlertContentAndInput);
divAlertOuter.appendChild(divAlerPromptButton);
divAlertOuter.appendChild(divAlertConfirm);
divAlertOuter.appendChild(divAlertButton);
divAlert.appendChild(divAlertOuter);
document.body.appendChild(divAlert);
document.body.addEventListener("keydown", function (e) {
if (e.key === "Escape") {
promptCancel();
confirmNo();
}
});
}
global.myAlert = function (msg, callback) {
@ -114,6 +143,10 @@
prepare();
}
divAlert.classList.remove("prompt");
divAlert.classList.remove("choice");
divAlert.classList.remove("choice-inline");
divAlertContent.textContent = msg;
divAlertInput.style.display = "none";
divAlertConfirm.style.display = "none";
@ -125,25 +158,29 @@
global.myAlert.l10n = _;
global.myPrompt = function (msg, callback, defaultText) {
global.myPrompt = function (msg, callback, defaultText, options) {
if (!divAlert) {
prepare();
}
divAlert.classList.add("prompt");
divAlert.classList.remove("choice");
divAlert.classList.remove("choice-inline");
divAlertContent.textContent = msg;
divAlertInput.style.display = "";
divAlertInput.firstChild.value = defaultText || "";
alertInput.style.display = "";
alertInput.value = defaultText || "";
alertInput.type = (options && options.type) || "text";
alertSelect.style.display = "none";
divAlertConfirm.style.display = "none";
divAlertButton.style.display = "none";
divAlertCallback = callback;
divAlert.style.display = "";
// eslint-disable-next-line require-unicode-regexp
if (!(/iPad|iPhone|iPod/g).test(navigator.userAgent)) {
alertInput.focus();
alertInput.setSelectionRange(0, alertInput.value.length);
alertInput.select();
}
alertInput.focus();
alertInput.setSelectionRange(0, alertInput.value.length);
alertInput.select();
};
global.myConfirm = function (msg, callbackYes, callbackNo) {
@ -151,6 +188,10 @@
prepare();
}
divAlert.classList.remove("prompt");
divAlert.classList.remove("choice");
divAlert.classList.remove("choice-inline");
divAlertContent.textContent = msg;
divAlertInput.style.display = "none";
divAlertConfirm.style.display = "";
@ -160,4 +201,35 @@
divAlert.style.display = "";
divAlertConfirm.getElementsByTagName("button")[0].focus();
};
global.myChoice = function (msg, options, callback, defaultValue) {
if (!divAlert) {
prepare();
}
divAlert.classList.remove("prompt");
divAlert.classList.add("choice");
if (options.dispositionInline) {
divAlert.classList.add("choice-inline");
} else {
divAlert.classList.remove("choice-inline");
}
alertSelect.options.length = 0;
for (const key of options.choices) {
[].push.call(alertSelect.options, new Option(key, key));
}
alertSelect.value = alertInput.value = defaultValue;
divAlertContent.textContent = msg;
divAlertInput.style.display = "";
alertInput.style.display = "none";
alertSelect.style.display = "";
divAlertConfirm.style.display = "none";
divAlertButton.style.display = "none";
divAlertCallback = callback;
divAlert.style.display = "";
divAlertConfirm.getElementsByTagName("button")[0].focus();
};
}(this));

View File

@ -1,23 +1,178 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg2" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" height="319mm" width="331mm" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1172.8346 1130.315" xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs id="defs4">
<linearGradient id="linearGradient5620" y2="482.82" gradientUnits="userSpaceOnUse" x2="1120.7" gradientTransform="matrix(1.21 0 0 1.21 -122.4 -73.147)" y1="482.82" x1="56.525">
<stop id="stop5616" offset="0"/>
<stop id="stop5618" stop-color="#33333f" stop-opacity=".94118" offset="1"/>
</linearGradient>
</defs>
<metadata id="metadata7">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" transform="translate(0 77.953)">
<path id="path3348" d="m510.26 107.75-273.12 245.46-127.91 449.43 490.91 207.46 456.36-183.26-159.04-487.46-221.26-224.71 190.18-148.75c-88.433-9.4796-177.32-14.756-266.25-15.804-96.89-1.1424-193.84 2.7337-290.33 11.607l200.46 146.03z" fill-rule="evenodd" stroke="#000" stroke-width="1.21px" fill="url(#linearGradient5620)"/>
<path id="path4164" stroke-linejoin="round" d="m684.88 431.89c-6.34-58.38-23.22-115.59-49.58-168.06-29.85-59.42-71.88-112.69-122.72-155.55 22.722 2.9086 45.556 4.9435 68.435 6.0986 34.007 1.717 68.112 1.489 102.09-0.68242" stroke="#b47f58" stroke-linecap="round" stroke-width="12.1" fill="none"/>
</g>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="44.867752mm"
height="49.999989mm"
viewBox="0 0 44.867752 49.999989"
version="1.1"
id="svg1697"
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
sodipodi:docname="bag.svg">
<defs
id="defs1691">
<linearGradient
inkscape:collect="always"
id="linearGradient1660">
<stop
style="stop-color:#09090b;stop-opacity:1;"
offset="0"
id="stop1656" />
<stop
style="stop-color:#4d4d4d;stop-opacity:1"
offset="1"
id="stop1658" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1660"
id="linearGradient21771"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.39152193,0,0,0.39152193,84.466516,149.67134)"
x1="91.671478"
y1="168.91321"
x2="133.35805"
y2="141.68517" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8.1152753"
inkscape:cx="117.01316"
inkscape:cy="196.52791"
inkscape:document-units="mm"
inkscape:current-layer="g1103"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:document-rotation="0"
inkscape:window-width="2560"
inkscape:window-height="1355"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata1694">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-83.071219,-130.26509)">
<g
id="g21769"
transform="matrix(2.003524,0,0,2.003524,-83.36396,-180.90033)">
<g
transform="matrix(1.2748214,0,0,1.2748214,-24.608503,-35.495168)"
id="g21732">
<g
id="g21827"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<g
id="g30492"
transform="matrix(0.21729684,-0.08669208,0.08669208,0.21729684,103.68655,158.98295)"
inkscape:transform-center-x="1.5006087"
inkscape:transform-center-y="1.3093051"
inkscape:export-filename="/home/id/Images/sac-trivabble-2.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<g
id="g1103"
transform="translate(2.4703087,2.0230148)">
<path
sodipodi:nodetypes="cccsccc"
inkscape:connector-curvature="0"
id="path30413"
d="m -84.900689,0.28001829 21.833764,0.3059734 -0.191029,1.50175751 c 0,0 -0.441181,4.067829 -0.336299,4.4757263 0.104885,0.4078974 -0.117732,2.1912659 -0.117732,2.1912659 0,0 -6.097547,-0.2961214 -7.045738,-0.3032108 L -84.881739,8.2721414"
style="fill:#fff6d5;fill-opacity:1;stroke:#fff6d5;stroke-width:0.0385405px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<g
transform="matrix(0.1825681,0.00267522,-5.184421e-5,0.16882308,-49.009855,-10.969319)"
id="g30409">
<g
id="g30385"
transform="matrix(0.87918095,0,0,0.87918095,-40.911317,12.434453)">
<rect
y="68.081581"
x="-173.92935"
height="48.242859"
width="48.301006"
id="rect30310-1"
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ccccaa;stroke-width:3.89295;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill" />
<rect
y="67.010086"
x="-174.99074"
height="49.229862"
width="49.229862"
id="rect30310"
style="opacity:1;fill:#eeee88;fill-opacity:1;fill-rule:nonzero;stroke:#aaaa55;stroke-width:1.75622;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill" />
</g>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.77114px;line-height:1.25;font-family:'Latin Modern Sans';-inkscape-font-specification:'Latin Modern Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#806600;fill-opacity:1;stroke:none;stroke-width:0.442784;"
x="-82.837639"
y="4.1053796"
id="text1081"
transform="rotate(1.013842)"><tspan
sodipodi:role="line"
id="tspan1079"
x="-82.837639"
y="4.1053796"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.77114px;font-family:'Latin Modern Sans';-inkscape-font-specification:'Latin Modern Sans Bold';stroke-width:0.442784;fill:#806600;">T R I</tspan><tspan
sodipodi:role="line"
x="-82.837639"
y="6.3193045"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.77114px;font-family:'Latin Modern Sans';-inkscape-font-specification:'Latin Modern Sans Bold';stroke-width:0.442784;fill:#806600;"
id="tspan1083">V A B</tspan><tspan
sodipodi:role="line"
x="-82.837639"
y="8.5332298"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.77114px;font-family:'Latin Modern Sans';-inkscape-font-specification:'Latin Modern Sans Bold';stroke-width:0.442784;fill:#806600;"
id="tspan1085">B L E</tspan></text>
</g>
</g>
<path
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
sodipodi:nodetypes="ccccscscc"
inkscape:connector-curvature="0"
id="path1652"
d="m 94.131223,152.51272 c -5.601088,2.15982 -8.233041,11.88313 -3.709692,15.57743 2.259612,1.4289 6.369375,1.78248 9.291522,-0.0477 5.117667,-3.5149 0.294817,-14.63396 -2.423845,-15.52974 1.56157,-1.70471 3.824372,-2.5464 2.46388,-2.56784 -0.474725,-0.007 -1.492125,0.22989 -3.33512,0.53701 -2.196265,0.38356 -2.12874,-0.27007 -4.726992,-0.73164 -0.878233,-0.15601 0.616117,1.29874 2.440247,2.76245 z"
style="fill:url(#linearGradient21771);fill-opacity:1;stroke:#333333;stroke-width:0.13229166px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
sodipodi:nodetypes="czcccc"
inkscape:connector-curvature="0"
id="path1654"
d="m 97.39512,152.3988 c 0,0 -1.151212,0.28745 -1.712317,0.29637 -0.5611,0.009 -1.74813,-0.18245 -1.74813,-0.18245 0,0 1.437,1.19372 1.913505,1.81901 0.893507,1.20756 1.341904,2.74231 1.50009,4.15773 v 0"
style="fill:none;stroke:#a05a2c;stroke-width:0.39687499;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

110
public/boards.js Normal file
View File

@ -0,0 +1,110 @@
window.BoardList = {
"8x8-7": {
factor: 0.3,
premium: 50,
TW: ["A1", "A8", "H1", "H8"],
DW: ["B2", "B7", "E5", "G2", "G7"],
TL: ["B5", "E2", "D7", "G4"],
DL: ["A4", "C3", "C6", "D1", "E8", "F3", "F6", "H5"],
CS: ["D4"]
},
"9x9-8": {
factor: 0.4,
premium: 65,
TW: ["A1", "A9", "I1", "I9"],
DW: ["B2", "C7", "G3", "H8"],
TL: ["B5", "C3", "D6", "E2", "E8", "F4", "G7", "H5"],
DL: ["A4", "A6", "B8", "D1", "D4", "D9", "F1", "F6", "F9", "H2", "I4", "I6"],
CS: ["E5"]
},
"8x15-7": {
factor: 0.6,
premium: 50,
TW: ["A1", "A8", "A15", "H1", "H8", "H15"],
DW: ["B2", "C3", "C10", "E9", "F6", "F13", "G14"],
TL: ["B6", "B13", "C14", "D11", "E5", "F2", "G3", "G10"],
DL: ["A5", "A12", "B4", "B9", "B11", "C8", "D2", "D4", "D15", "E1", "E12", "E14", "F8", "G5", "G7", "G12", "H4", "H11"],
CS: ["D7"]
},
"9x17-8": {
factor: 0.7,
premium: 65,
TW: ["A1", "A9", "A17", "I1", "I9", "I17"],
DW: ["B2", "B16", "C3", "C15", "F10", "G3", "G15", "H2", "H16"],
TL: ["B6", "B12", "C7", "C11", "D14", "E5", "E13", "F4", "G7", "G11", "H6", "H12"],
DL: ["A5", "A13", "B4", "C13", "D1", "D4", "D10", "D17", "E2", "E9", "E16", "F1", "F8", "F14", "F17", "G5", "H14", "I5", "I13"],
CS: ["D8"]
},
"13x13-6": {
factor: 0.75,
premium: 35,
TW: ["A1", "A7", "A13", "G1", "G13", "M1", "M7", "M13"],
DW: ["B2", "B12", "C3", "C11", "D4", "D10", "J4", "J10", "K3", "K11", "L2", "L12"],
TL: ["B5", "B9", "E2", "E12", "F6", "F8", "H6", "H8", "I2", "I12", "L5", "L9"],
DL: ["A4", "A10", "C6", "C8", "D1", "D7", "D13", "E5", "E9", "F3", "F11", "G4", "G10", "H3", "H11", "I5", "I9", "J1", "J7", "J13", "K6", "K8", "M4", "M10"],
CS: ["G7"]
},
"8x22-7": {
factor: 0.8,
premium: 50,
TW: ["A1", "A8", "A15", "A22", "H1", "H8", "H15", "H22"],
DW: ["B3", "B10", "B18", "C4", "C11", "C19", "E5", "E21", "G7", "G15", "G23", "H8", "H16", "H24"],
TL: ["B3", "B13", "B17", "C2", "C10", "C16", "D5", "E18", "F7", "F13", "F21", "G6", "G10", "G20"],
DL: ["A5", "A11", "A19", "B9", "C14", "D8", "D19", "D22", "E1", "E4", "E15", "F9", "G14", "H4", "H12", "H18"],
CS: ["D11"]
},
"9x25-8": {
factor: 1,
premium: 65,
TW: ["A1", "A9", "A17", "A25", "I1", "I9", "I17", "I25"],
DW: ["B2", "B10", "B18", "C3", "C19", "E5", "E21", "G7", "G23", "H8", "H16", "H24"],
TL: ["B6", "B14", "B22", "C7", "C15", "D8", "D16", "D24", "F2", "F10", "F18", "G11", "G19", "H4", "H12", "H20"],
DL: ["A5", "A13", "A21", "C11", "C23", "D4", "D12", "D20", "E1", "E9", "E17", "E25", "F6", "F14", "F22", "G3", "G15", "I5", "I13", "I21"],
CS: ["E13"]
},
"15x15-7": {
factor: 1,
premium: 50,
TW: ["A1", "A8", "A15", "H1", "H15", "O1", "O8", "O15"],
DW: ["B2", "B14", "C3", "C13", "D4", "D12", "E5", "E11", "K5", "K11", "L4", "L12", "M3", "M13", "N2", "N14"],
TL: ["B6", "B10", "F2", "F6", "F10", "F14", "J2", "J6", "J10", "J14", "N6", "N10"],
DL: ["A4", "A12", "C7", "C9", "D1", "D8", "D15", "G3", "G7", "G9", "G13", "H4", "H12", "I3", "I7", "I9", "I13", "L1", "L8", "L15", "M7", "M9", "O4", "O12"],
CS: ["H8"]
},
"17x17-8": {
factor: 1.3,
premium: 65,
TW: ["A1", "A9", "A17", "I1", "I17", "Q1", "Q9", "Q17"],
DW: ["B2", "B16", "C3", "C15", "D4", "D14", "E5", "E13", "M5", "M13", "N4", "N14", "O3", "O15", "P2", "P16"],
TL: ["B6", "B12", "C7", "C11", "F2", "F16", "G3", "G7", "G11", "G15", "K3", "K7", "K11", "K15", "L2", "L16", "O7", "O11", "P6", "P12"],
DL: ["A5", "A13", "D8", "D10", "E1", "E9", "E17", "F6", "F12", "H4", "H8", "H10", "H14", "I5", "I13", "J4", "J8", "J10", "J14", "L6", "L12", "M1", "M9", "M17", "N8", "N10", "Q5", "Q13"],
CS: ["I9"]
},
"19x19-6": {
factor: 1.6,
premium: 35,
TW: ["A1", "A7", "A13", "A19", "G1", "G7", "G13", "G19", "M1", "M7", "M13", "M19", "S1", "S7", "S13", "S19"],
DW: ["B2", "B8", "B18", "C3", "C17", "D4", "D10", "D16", "H9", "H18", "J4", "J16", "L2", "L11", "P4", "P10", "P16", "Q3", "Q17", "R2", "R12", "R18"],
TL: ["B5", "B15", "C11", "E2", "E8", "E12", "E18", "F6", "F14", "H5", "H15", "I3", "I12", "K8", "K17", "L5", "L15", "N6", "N14", "O2", "O8", "O12", "O18", "Q9", "R5", "R15"],
DL: ["A4", "A10", "A16", "B12", "C6", "C9", "C14", "D1", "D7", "D13", "D19", "E5", "E15", "F3", "F9", "F11", "F17", "G4", "G10", "G16", "H2", "H11", "I6", "I8", "I14", "I17", "J1", "J7", "J13", "J19", "K3", "K6", "K12", "K14", "L9", "L18", "M4", "M10", "M16", "N3", "N9", "N11", "N17", "O5", "O15", "P1", "P7", "P13", "P19", "Q6", "Q11", "Q14", "R8", "S4", "S10", "S16"],
CS: ["J10"]
},
"22x22-7": {
factor: 2,
premium: 50,
TW: ["A1", "A8", "A15", "A22", "H1", "H8", "H15", "H22", "O1", "O8", "O15", "O22", "V1", "V8", "V15", "V22"],
DW: ["B2", "B10", "B21", "C3", "C20", "D4", "D12", "D19", "E5", "E18", "I9", "I14", "J21", "K4", "L12", "L19", "M2", "N9", "N14", "R5", "R18", "S4", "S11", "S19", "T3", "T20", "U2", "U13", "U21"],
TL: ["B6", "B17", "E14", "F2", "F6", "F10", "F17", "F21", "I5", "J13", "J17", "M6", "M10", "N18", "Q2", "Q6", "Q13", "Q17", "Q21", "R9", "U6", "U17"],
DL: ["A4", "A12", "A19", "B13", "C7", "C11", "C16", "D1", "D8", "D15", "D22", "E9", "F13", "G3", "G7", "G11", "G16", "G20", "H4", "H12", "H19", "I18", "J2", "J6", "J10", "K1", "K8", "K16", "K20", "L3", "L7", "L15", "L22", "M13", "M17", "M21", "N5", "O4", "O11", "O19", "P3", "P7", "P12", "P16", "P20", "Q10", "R14", "S1", "S8", "S15", "S22", "T7", "T12", "T16", "U10", "V4", "V11", "V19"],
CS: ["K11"]
},
"25x25-8": {
factor: 2.8,
premium: 65,
TW: ["A1", "A9", "A17", "A25", "I1", "I9", "I17", "I25", "Q1", "Q9", "Q17", "Q25", "Y1", "Y9", "Y17", "Y25"],
DW: ["B2", "B24", "D4", "D14", "D22", "E5", "E13", "E21", "F12", "H8", "H18", "L4", "L20", "M5", "M21", "N6", "N22", "R8", "R18", "T14", "U5", "U13", "U21", "V4", "V12", "V22", "X2", "X24"],
TL: ["C3", "C7", "C11", "C15", "C19", "C23", "G3", "G7", "G11", "G15", "G19", "G23", "K3", "K7", "K11", "K15", "K19", "K23", "O3", "O7", "O11", "O15", "O19", "O23", "S3", "S7", "S11", "S15", "S19", "S23", "W3", "W7", "W11", "W15", "W19", "W23"],
DL: ["A5", "A13", "A21", "B6", "B12", "B16", "B20", "D10", "D18", "E1", "E9", "E17", "E25", "F2", "F6", "F16", "F20", "F24", "H4", "H14", "I5", "I13", "I21", "J2", "J6", "J10", "J16", "J22", "L8", "L12", "L24", "M1", "M9", "M17", "M25", "N2", "N14", "N18", "P4", "P10", "P16", "P20", "P24", "Q5", "Q13", "Q21", "R12", "R22", "T2", "T6", "T10", "T20", "T24", "U1", "U9", "U17", "U25", "V8", "V16", "X6", "X10", "X14", "X20", "Y5", "Y13", "Y21"],
CS: ["M13"]
}
};

View File

@ -3,19 +3,58 @@
window.TrivabbleConf = {
// The amount of time to wait after a connection failure
POLLING_DELAY: 2000,
//POLLING_DELAY: 2000,
// Whether WebSockets should be used, if possible
ENABLE_WEBSOCKETS: true,
//ENABLE_WEBSOCKETS: true,
// Whether Server Sent Events should be used, if available
ENABLE_EVENT_SOURCE: true,
//ENABLE_EVENT_SOURCE: true,
// Max consecutive tries before blacklisting WebSockets for the current session
MAX_WEBSOCKET_ERRORS: 1,
//MAX_WEBSOCKET_ERRORS: 1,
// to tweak only if your webserver is shared with other conflicting resources at / ( ex: yunohost integration )
APP_PATH: "",
// To tweak only if your webserver is shared with other conflicting resources at / (e.g. Yunohost integration)
//APP_PATH: "",
// The API entry point. Default value: APP_PATH + '/:trivabble'
//API_ENTRY_POINT: "/:trivabble",
// Wether sounds should be played when receiving messages
//ENABLE_MSG_SOUND: true,
// Wether sounds should be played when moving tiles
//ENABLE_TILE_SOUND: true,
// The list of durations used to detect a double tap available in the settings box
//DOUBLE_TAP_DURATIONS: [650, 1100, 1800, 3000, 5000],
// The defaut double tap duration. If not set, the value at the middle of the previous array is used.
//DOUBLE_TAP_DURATION: 1800,
// The color of the flash light when double clicking on a cell
//FLASH_LIGHT_COLOR: "#EE6633",
// The list of durations of the flash light available in the settings box
//FLASH_LIGHT_DURATIONS: [800, 1600, 3200],
// The defaut flash light duration. If not set, the value at the middle of the previous array is used.
//FLASH_LIGHT_DURATION: 1600,
// The default premium for playing seven tiles on a turn
//PREMIUM_SEVEN_TILES: 50,
// Score is automically affected to last player. If false, score is automatically affected to the player who pressed the Score button
//SCORE_LAST_PLAYER: true,
// Timer activation
//ENABLE_TIMER: false,
// Cell captions. Could be "clip", "dots", "none" or "short"
//CELL_CAPTIONS: "dots",
// Enable custom board definitions
//ENABLE_CUSTOM_BOARD: false,
// I don't like trailing commas, here is a nice message for you reading this file :-)
HAVE_FUN: true

View File

@ -8,14 +8,22 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="format-detection" content="telephone=no" />
<script src="boards.js"></script>
<script src="config.js"></script>
<script src="dict/list.js"></script>
<script src="l10n.js"></script>
<script src="alert.js"></script>
<script src="touch2click.js"></script>
<script src="trivabble.js"></script>
<link rel="icon" type="image/svg+xml" href="logo/path.svg" />
<link rel="icon" type="image/png" href="logo/16.png" sizes="16x16" />
<link rel="icon" type="image/png" href="logo/32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="logo/86.png" sizes="86x86" />
<link rel="icon" type="image/png" href="logo/180.png" sizes="180x180" />
<link rel="icon" type="image/png" href="logo/192.png" sizes="192x192" />
</head>
<body>
<div id="menu">
<div id="menu" class="panel">
<button data-l10n="text-content" id="join-game">Join adversaries</button>
<p id="p-name"> <span data-l10n="text-content">You are:</span> <span id="name" data-l10n="text-content">(name to give)</span><br /><button class="minibutton" id="change-name" data-l10n="text-content">Change</button></p>
<button id="clear-game" data-l10n="text-content">Put back all the tiles&#10;in the bag</button>
@ -23,33 +31,100 @@
<div id="chat-messages"></div>
<textarea id="chat-ta" placeholder="Write a message to your adversaries here" data-l10n="placeholder"></textarea>
<button id="chat-btn" class="minibutton" data-l10n="text-content">Send message</button>
<div id="prefs-sound">
<p><label><input type="checkbox" id="tiles-sound" checked="checked" /><span data-l10n="text-content">Sound of the tiles</span></label></p>
<p><label><input type="checkbox" id="msg-sound" checked="checked" /><span data-l10n="text-content">Sound of messages</span></label></p>
</div>
<div id="lang-selection">
<label>
<span data-l10n="text-content">Interface language: </span>
<div id="board-selection">
<p>
<label for="select-lang" data-l10n="text-content">Interface language: </label>
<select id="select-lang">
<option value="en">English</option>
<option value="fr">Français</option>
<option value="br">Brezhoneg</option>
<option value="ro">Română</option>
</select>
</label>
</div>
<div id="board-lang-selection" style="display:none">
<label>
<span data-l10n="text-content">Board language: </span>
</p>
<p id="board-lang-selection" hidden="true">
<label for="board-lang" data-l10n="text-content">Board language: </label>
<select id="board-lang">
<option value="fr">French</option>
</select>
</label>
</p>
<p id="board-label-selection" hidden="true">
<label for="board-label" data-l10n="text-content">Board configuration: </label>
<select id="board-label">
<option value="15x15-7">15x15-7</option>
</select>
</p>
</div>
</div>
<div id="content">
<section class="modal" id="modal-settings-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 data-l10n="text-content">Settings</h1>
<button class="modal-button" id="btn-settings-close">&#215;</button>
</div>
<div>
<p><label><input type="checkbox" id="enable-timer" /> <span data-l10n="text-content">Show the timer</span></label></p>
</div>
<div>
<p><label><input type="checkbox" id="tiles-sound" /><span data-l10n="text-content">Sound of the tiles</span></label></p>
<p><label><input type="checkbox" id="msg-sound" /><span data-l10n="text-content">Sound of messages</span></label></p>
</div>
<div>
<p id="disable-spell-checker-p" hidden="true">
<label>
<input type="checkbox" id="disable-spell-checker" />
<span data-l10n="text-content">Disable the spell checker</span>
</label>
</p>
<p id="no-spell-checker-p" hidden="false">
<span data-l10n="text-content">Spell checking is not available for this language.</span>
</p>
</div>
<div>
<p>
<label for="double-tap-duration" data-l10n="text-content">Double tap duration:</label>
<span class="span-range">
<span data-l10n="text-content">(fast)</span>
<input type="range" min="0" max="0" id="double-tap-duration" />
<span data-l10n="text-content">(slow)</span><br/>
</span>
</p>
</div>
<div>
<p>
<label for="flash-light-duration" data-l10n="text-content">Flash light duration:</label>
<span class="span-range">
<span data-l10n="text-content">(fast)</span>
<input type="range" min="0" max="0" id="flash-light-duration" />
<span data-l10n="text-content">(slow)</span>
</span>
</p>
</div>
<div>
<p id="flash-light-color-p">
<label>
<input type="color" size="6" id="flash-light-color" />
<span data-l10n="text-content">Flash light color</span>
</label>
</p>
</div>
<div>
<p id="cell-captions-p">
<label>
<span data-l10n="text-content">Cell captions:</span>
<select id="cell-captions">
<option value="clip" data-l10n="text-content">Clip when overflow</option>
<option value="dots" data-l10n="text-content">Dots when overflow</option>
<option value="none" data-l10n="text-content">No caption</option>
<option value="short" data-l10n="text-content">Short caption</option>
</select>
</label>
</p>
</div>
</div>
</section>
<div id="content">
<table id="board">
<tr><td class="corner"></td></tr>
</table>
@ -58,17 +133,40 @@
</div>
</div>
<div id="panel">
<div id="panel" class="panel">
<div id="btn-settings-and-timer">
<button id="btn-settings" data-l10n="text-content">Settings</button>
<p id="timer" hidden="true">
<span data-l10n="text-content">Turn:</span> <span id="timer-turn">--</span> / <span id="timer-game">--</span>
</p>
</div>
<div id="bag"></div>
<p><span data-l10n="text-content">Number of tiles in the bag:</span><br /><span id="remaining-letters">102</span><br /><span id="help-bag" data-l10n="text-content">Click on it to take one.</span><a href="#" id="help-clear" style="display:none"></a></p>
<p><span data-l10n="text-content">Number of tiles in the bag:</span><br /><span id="remaining-letters">102</span></p>
<table id="participants">
<tr><th data-l10n="text-content">Participant</th><th data-l10n="text-content">Rack</th><th data-l10n="text-content">Score</th><th data-l10n="text-content">Turn</th></tr>
<tr id="participants-placeholder"><td colspan="4" data-l10n="text-content">Waiting for other participants…</td></tr>
</table>
<p id="help-scores" data-l10n="text-content">Click on someone's score&#10;to change it.</p>
<p id="help-turn" data-l10n="text-content">Who's turn? Click on the Turn button!</p>
<button id="clear-rack" class="minibutton" data-l10n="text-content">Put back all the tiles of&#10;your rack in the bag</button>
<button id="show-rack" class="minibutton" data-l10n="text-content">Show my rack to other players</button>
<div id="panel-buttons">
<button id="clear-rack" class="minibutton" data-l10n="text-content">Put back all the tiles of&#10;your rack in the bag</button>
<button id="show-rack" class="minibutton" data-l10n="text-content">Show my rack to other players</button>
<button id="check-spelling" class="minibutton" data-l10n="text-content" hidden="true">Check spelling for new words</button>
<button id="score-words" class="minibutton" data-l10n="text-content">Score new words</button>
</div>
<div id="help-box">
<p id="help-box-title" data-l10n="text-content">Tip!</p>
<div id="help-box-inner">
<div id="help-messages">
<p data-l10n="text-content" hidden="true">Click on the bag to take one tile.</p>
<p data-l10n="text-content" hidden="true">Click on someone's score&#10;to change it.</p>
<p data-l10n="text-content" hidden="true">Who's turn? Click on the Turn button!</p>
<p data-l10n="text-content" hidden="true">Click on (+) to increase someone's score.</p>
<p data-l10n="text-content" hidden="true">Show a cell to everyone by double-clicking on it.</p>
<p data-l10n="text-content" hidden="true">To measure playing time, activate the timer.</p>
</div>
<button id="next-help-msg" class="minibutton" data-l10n="title" title="Next tip"></button>
</div>
</div>
<p id="info-spell-checking" hidden="true"><span data-l10n="text-content">Spell checking is based on:</span> <a rel="noopener noreferrer" target="_blank" href="http://aspell.net">Aspell</a></p>
</div>
</body>
</html>

BIN
public/logo/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

BIN
public/logo/180.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
public/logo/192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
public/logo/32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
public/logo/86.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

212
public/logo/logo.svg Normal file
View File

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="66.145836mm"
height="66.078644mm"
viewBox="0 0 66.145836 66.078644"
version="1.1"
id="svg33266"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="logo.svg">
<defs
id="defs33260" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4826594"
inkscape:cx="216.83666"
inkscape:cy="216.09552"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:document-rotation="0"
inkscape:window-width="2560"
inkscape:window-height="1355"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1">
<sodipodi:guide
position="64.454693,27.711101"
orientation="0,1"
id="guide33349"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata33263">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-27.05171,-93.927608)">
<g
id="g30409"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,308.75047,-7.1664876)">
<g
transform="matrix(0.87918095,0,0,0.87918095,-40.911317,12.434453)"
id="g30385">
<rect
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ccccaa;stroke-width:3.89294624;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
id="rect30310-1"
width="48.301006"
height="48.242859"
x="-173.92935"
y="68.081581" />
<rect
style="opacity:1;fill:#eeee88;fill-opacity:1;fill-rule:nonzero;stroke:#aaaa55;stroke-width:1.75621903;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
id="rect30310"
width="49.229862"
height="49.229862"
x="-174.99074"
y="67.010086" />
</g>
<g
transform="translate(-98.735177,20.673278)"
style="fill:#000000"
id="g30330" />
</g>
<g
id="g892"
transform="translate(-3.8920143,1.8276076)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;line-height:1;font-family:LilyUPC;-inkscape-font-specification:'LilyUPC, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.31716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
x="-91.001099"
y="63.331829"
id="text30272"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,166.60077,22.343531)"><tspan
sodipodi:role="line"
id="tspan30270"
x="-91.001099"
y="63.331829"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke-width:1.31716">T</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;line-height:1;font-family:LilyUPC;-inkscape-font-specification:'LilyUPC, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.31716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
x="-77.750885"
y="63.331829"
id="text30276"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,166.60077,22.343531)"><tspan
sodipodi:role="line"
x="-77.750885"
y="63.331829"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke-width:1.31716"
id="tspan30278">R</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;line-height:1;font-family:LilyUPC;-inkscape-font-specification:'LilyUPC, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.31716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
x="-61.445587"
y="63.331829"
id="text30284"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,166.60077,22.343531)"><tspan
sodipodi:role="line"
id="tspan30282"
x="-61.445587"
y="63.331829"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke-width:1.31716">I</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;line-height:1;font-family:LilyUPC;-inkscape-font-specification:'LilyUPC, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.31716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
x="-91.318954"
y="77.142586"
id="text30288"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,166.60077,22.343531)"><tspan
sodipodi:role="line"
id="tspan30286"
x="-91.318954"
y="77.142586"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke-width:1.31716">V</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;line-height:1;font-family:LilyUPC;-inkscape-font-specification:'LilyUPC, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.31716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
x="-77.862938"
y="77.188324"
id="text30292"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,166.60077,22.343531)"><tspan
sodipodi:role="line"
id="tspan30290"
x="-77.862938"
y="77.188324"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke-width:1.31716">A</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;line-height:1;font-family:LilyUPC;-inkscape-font-specification:'LilyUPC, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.31716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
x="-63.890118"
y="77.188324"
id="text30296"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,166.60077,22.343531)"><tspan
sodipodi:role="line"
id="tspan30294"
x="-63.890118"
y="77.188324"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke-width:1.31716">B</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;line-height:1;font-family:LilyUPC;-inkscape-font-specification:'LilyUPC, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.31716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
x="-91.5522"
y="91.044815"
id="text30300"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,166.60077,22.343531)"><tspan
sodipodi:role="line"
id="tspan30298"
x="-91.5522"
y="91.044815"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke-width:1.31716">B</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;line-height:1;font-family:LilyUPC;-inkscape-font-specification:'LilyUPC, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.31716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
x="-77.39415"
y="91.044815"
id="text30304"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,166.60077,22.343531)"><tspan
sodipodi:role="line"
id="tspan30302"
x="-77.39415"
y="91.044815"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke-width:1.31716"
rotate="0 0">L</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;line-height:1;font-family:LilyUPC;-inkscape-font-specification:'LilyUPC, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.31716;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
x="-63.451061"
y="91.044815"
id="text30308"
transform="matrix(1.4391919,0.00245906,-0.00245906,1.4391919,166.60077,22.343531)"><tspan
sodipodi:role="line"
id="tspan30306"
x="-63.451061"
y="91.044815"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.6683px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke-width:1.31716">E</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.0366029px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 91.191608,121.7174 -0.580184,0.38267"
id="path30411"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

1
public/logo/path.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -1,3 +1,7 @@
:root {
--flash-light-color: #ee6633;
}
#board {
border-collapse:collapse;
}
@ -47,7 +51,7 @@ html, #board, [draggable], .tile {
color: green;
}
#clear-game, #help-scores, #clear-rack, #help-turn {
#clear-game, #clear-rack {
white-space:pre-wrap;
}
@ -57,7 +61,7 @@ html, #board, [draggable], .tile {
-webkit-user-drag: element;
}
#help-clear, #help-bag, #help-scores, #help-turn {
#help-message {
font-size:small
}
@ -75,6 +79,9 @@ html, #board, [draggable], .tile {
width: 100%;
top: 0px;
left: 0px;
display: -webkit-flex;
-webkit-justify-content: center;
-webkit-flex-direction: column;
display: flex;
justify-content: center;
flex-direction: column;
@ -115,6 +122,23 @@ html, #board, [draggable], .tile {
display:inline-block;
white-space:pre-wrap;
font-size:7px;
overflow:hidden;
}
.special-cell-label-clip .special-cell-label {
text-overflow:clip;
}
.special-cell-label-dots .special-cell-label {
text-overflow:ellipsis;
}
.special-cell-label-none .special-cell-label {
visibility:hidden;
}
.special-cell-label-short .special-cell-label {
display:inline;
}
#center-cell .special-cell-label {
@ -141,23 +165,36 @@ body {
display:-webkit-flex;
display:flex;
-webkit-flex-direction:column;
flex-direction:column
flex-direction:column;
}
button {
margin: 0.25em 0;
min-height:3em;
background:#AFA;
border:1px solid gray;
border-radius: 2px;
}
button:hover {
background:#FD7;
cursor:pointer
.panel button {
margin: 0.25em 0;
min-height:3em;
background: #CFC;
border: 1px solid #8C8;
cursor: pointer;
transition: 0.2s;
}
.panel button:hover {
background: #FD7;
border: 1px solid #CA5;
}
.panel button[disabled=disabled], .panel button:disabled {
background:#AFA;
cursor:not-allowed;
}
#rack {
background:#EEC;
z-index:10;
font-size:0;
border-radius:4px;
display:inline-block;
@ -167,8 +204,10 @@ button:hover {
}
#board td {
width:32px;
height:32px;
width: 32px;
max-width:32px;
max-height:32px;
}
#rack .tile-placeholder {
@ -192,6 +231,14 @@ button:hover {
cursor:pointer
}
.tile.tile-spelling-ok {
background-color: #3E3;
}
.tile.tile-spelling-nok {
background-color: #E33;
}
.tile.tile-highlight {
background-color: #FFF;
font-weight: bold;
@ -210,6 +257,19 @@ button:hover {
}
}
.flash-light-highlighting .tile {
transition:none;
}
.flash-light-highlight {
background-color: #ee6633;
background-color: var(--flash-light-color);
}
.flash-light-highlight .tile:not(.tile-highlight) {
background-color: inherit;
}
.tile-score {
font-size: 0.5em;
position: absolute;
@ -309,9 +369,9 @@ td.blink {
}
#panel {
-webkit-justify-content:center;
justify-content:center;
text-align:center
/* -webkit-justify-content:center; does not look good */
justify-content:space-between;
text-align:center;
}
#bag, #rack-outer {
@ -325,8 +385,8 @@ td.blink {
font-size:small
}
.minibutton {
padding:0;
.panel .minibutton {
padding:0.25ex 0.5ex;
min-height:0;
font-size:small
}
@ -343,7 +403,7 @@ td.blink {
width:165px;
height:160px;
background:url(bag.svg) no-repeat;
background-size:100% 100%
background-size:100% 100%;
}
#bag:hover {
@ -373,7 +433,7 @@ td.blink {
#participants th, #participants td {
border:1px solid gray;
padding:0.33ex 0.5ex
padding:0.33ex 0.5ex;
}
#participants .score-cell > span {
@ -381,15 +441,16 @@ td.blink {
min-width:2.5em;
}
#participants .score-cell > span:hover, .turn-cell button:hover {
#participants .score-cell > span:hover, #participants .turn-cell button:hover {
cursor:pointer;
background:#FFA
}
#participants .score-cell button {
min-height:4ex; /* for old webkit */
min-height: auto;
font-size:x-small;
padding:0 0.5ex;
padding:0 1ex;
margin:0;
background:#CCC;
color:back;
@ -410,7 +471,7 @@ td.blink {
font-style:italic;
}
.turn-cell button {
#participants .turn-cell button {
padding:0 2px;
background:white;
min-height:1em;
@ -419,7 +480,7 @@ td.blink {
display:flex;
}
.turn-cell img {
#participants .turn-cell img {
width:1em;
vertical-align: middle;
}
@ -443,20 +504,263 @@ td.blink {
}
}
#prefs-sound {
margin:1ex 0 0 0;
}
#prefs-sound p {
#modal-settings-dialog p {
margin:0;
padding:0;
font-size:small
}
#lang-selection, #board-lang-selection {
font-size:small;
}
#prefs-sound input, #prefs-sound label {
vertical-align:middle
#modal-settings-dialog label span, #modal-settings-dialog label input {
display: inline-block;
vertical-align: middle;
}
#lang-selection {
display:table;
}
#lang-selection p {
display:table-row;
}
#lang-selection p:first-child select {
margin-bottom:0.5ex;
}
#lang-selection select, #lang-selection label {
display:table-cell;
vertical-align:middle;
font-size:small;
}
#lang-selection select {
width:100%;
}
#lang-selection label {
padding-right:0.5ex;
}
.modal {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
visibility: hidden;
-webkit-transition: visibility 0s linear 0.25s, opacity 0.25s 0s;
transform: scale(1.1);
transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
z-index: 1;
}
.modal-header {
display:flex;
flex-direction:row;
}
.modal-header h1 {
flex:1;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 1rem 1.5rem;
width: 24rem;
border-radius: 0.3rem;
}
#btn-settings-close {
font-weight: bold;
text-align: center;
border: 0;
}
.modal-content h1 {
margin: 0px;
font-weight: bold;
font-size: large;
}
.modal-button {
float: right;
width: 1.5rem;
line-height: 1.5rem;
text-align: center;
cursor: pointer;
border-radius: 0.25rem;
background-color: lightgray;
}
.modal-button:hover, #btn-settings:hover {
background-color: darkgray;
}
.show-modal {
opacity: 1;
visibility: visible;
-webkit-transition: visibility 0s linear 0s, opacity 0.25s 0s;
transform: scale(1.0);
transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}
.modal-content > div:not(:last-child) {
margin-bottom: 1ex;
}
.span-range {
display:block;
text-align:center;
}
.span-range > span {
font-size:smaller;
}
.span-range > span, .span-range > input {
display:inline-block;
vertical-align: middle;
}
.alert {
z-index: 2;
}
#panel #btn-settings {
background:lightgray;
color:black;
font-size:small;
border-radius:3px;
border:none;
margin:0;
min-height: 2em;
float:right
}
#panel #btn-settings-and-timer {
text-align:right;
}
#btn-settings:before {
content: "⚙️ "
}
#info-spell-checking {
font-size:small;
color:gray;
}
#info-spell-checking a {
color:black;
}
#help-messages {
box-sizing:border-box;
overflow:auto;
width: auto;
margin-bottom:1px;
}
#help-box {
margin-left:1ex;
margin-top:1ex;
display:-webkit-flex;
-webkit-flex-direction:column;
-webkit-justify-content:center;
-webkit-align-items:center;
align-items:center;
display:flex;
flex-direction:column;
justify-content:center;
}
#help-box-inner {
display:-webkit-flex;
-webkit-flex-direction:row;
display:flex;
flex-direction:row;
min-height:2em;
border-top:1px solid gray;
border-bottom:1px solid gray;
-webkit-align-items:center;
align-items:center;
}
button#next-help-msg {
border:0;
background:none;
color:#333;
font-size:1.5rem;
margin-right:0.5ex;
background:#F1F1F1;
border-radius:100rem;
height:1.5em;
width:1.5em;
font-weight:bold;
transition:500ms;
padding:0;
}
button#next-help-msg:hover {
background:#CCC;
}
#help-box-title {
margin:0;
padding:0 0 0.25ex 0;
text-align:right;
width:100%;
color:gray;
font-size:small;
font-style:italic;
}
#help-messages p {
margin:0;
font-size:0.9;
color:#222;
padding:0 0.5ex;
max-width:17em;
}
#help-box-inner:before {
content:"i";
display:inline-block;
height:1.2em;
width:1.2em;
font-style:italic;
font-weight:bold;
font-family:serif;
color:#AAA;
border:2px solid;
border-radius:100rem;
}
#panel-buttons {
display:-webkit-flex;
-webkit-flex-direction: column;
display:flex;
flex-direction:column;
}
#timer {
font-size:x-small;
text-align:center;
margin:0;
margin-right:1ex;
}
#timer > span {
white-space:nowrap;
}
#timer > span:first-child {
color:gray;
}

File diff suppressed because it is too large Load Diff

56
server/lang/af.json Normal file
View File

@ -0,0 +1,56 @@
{
"code": "af",
"name": "Afrikaans",
"bag": [
" ", " ",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I",
"D", "D", "D", "D", "D", "D",
"N", "N", "N", "N", "N", "N", "N", "N",
"O", "O", "O", "O", "O", "O",
"R", "R", "R", "R", "R", "R",
"S", "S", "S", "S", "S", "S",
"T", "T", "T", "T", "T", "T",
"G", "G", "G", "G",
"H", "H", "H",
"L", "L", "L",
"K", "K", "K",
"W", "W", "W",
"M", "M",
"U", "U",
"Y", "Y",
"P", "P",
"V", "V",
"B",
"F",
"J"
],
"letterValues": {
" ": 0,
"E": 1,
"A": 1,
"I": 1,
"D": 1,
"N": 1,
"O": 1,
"R": 1,
"S": 1,
"T": 1,
"G": 2,
"H": 2,
"L": 2,
"K": 3,
"W": 3,
"M": 4,
"U": 4,
"Y": 4,
"P": 5,
"V": 5,
"B": 8,
"F": 8,
"J": 10
}
}

76
server/lang/ar.json Normal file
View File

@ -0,0 +1,76 @@
{
"code": "ar",
"name": "Arabic",
"bag": [
" ", " ",
"", "", "", "", "", "", "", "",
"ﻝ", "ﻝ", "ﻝ", "ﻝ",
"ﺝ", "ﺝ", "ﺝ", "ﺝ",
"ح", "ح", "ح",
"ﺥ", "ﺥ", "ﺥ",
"ﻡ", "ﻡ", "ﻡ",
"ﻥ", "ﻥ", "ﻥ",
"", "", "",
"ﻭ", "ﻭ", "ﻭ",
"ﻯ", "ﻯ", "ﻯ",
"ﺏ", "ﺏ", "ﺏ", "ﺏ",
"ﺭ", "ﺭ", "ﺭ",
"ﺯ", "ﺯ", "ﺯ",
"ﺕ", "ﺕ", "ﺕ", "ﺕ",
"ﺩ", "ﺩ", "ﺩ",
"ﺫ", "ﺫ", "ﺫ",
"ﺱ", "ﺱ", "ﺱ",
"ﺵ", "ﺵ", "ﺵ",
"ﺙ", "ﺙ", "ﺙ",
"ﻑ", "ﻑ", "ﻑ",
"ﻕ", "ﻕ", "ﻕ",
"ﺹ", "ﺹ", "ﺹ",
"ﺽ", "ﺽ", "ﺽ",
"ﻉ", "ﻉ", "ﻉ",
"ﻙ", "ﻙ", "ﻙ",
"ﻁ", "ﻁ",
"ﻅ", "ﻅ",
"ئ", "ئ",
"ﻍ", "ﻍ",
"ء", "ء",
"أ", "أ",
"ؤ", "ؤ"
],
"letterValues": {
" ": 0,
"": 1,
"ﻝ": 1,
"ﺝ": 1,
"ح": 1,
"ﺥ": 1,
"ﻡ": 1,
"ﻥ": 1,
"": 1,
"ﻭ": 1,
"ﻯ": 1,
"ﺏ": 2,
"ﺭ": 2,
"ﺯ": 2,
"ﺕ": 2,
"ﺩ": 2,
"ﺫ": 2,
"ﺱ": 2,
"ﺵ": 2,
"ﺙ": 2,
"ﻑ": 2,
"ﻕ": 2,
"ﺹ": 3,
"ﺽ": 3,
"ﻉ": 3,
"ﻙ": 3,
"ﻁ": 3,
"ﻅ": 5,
"ئ": 6,
"ﻍ": 8,
"ء": 8,
"أ": 10,
"ؤ": 10
}
}

72
server/lang/bg.json Normal file
View File

@ -0,0 +1,72 @@
{
"code": "bg",
"name": "Bulgarian",
"bag": [
" ", " ", " ",
"А", "А", "А", "А", "А", "А", "А", "А", "А",
"О", "О", "О", "О", "О", "О", "О", "О", "О",
"Е", "Е", "Е", "Е", "Е", "Е", "Е", "Е",
"И", "И", "И", "И", "И", "И", "И", "И",
"Т", "Т", "Т", "Т", "Т",
"Н", "Н", "Н", "Н",
"П", "П", "П", "П",
"Р", "Р", "Р", "Р",
"С", "С", "С", "С",
"В", "В", "В", "В",
"М", "М", "М", "М",
"Б", "Б", "Б",
"Д", "Д", "Д",
"К", "К", "К",
"Л", "Л", "Л",
"Г", "Г", "Г",
"Ъ", "Ъ",
"Ж", "Ж",
"З", "З",
"У", "У", "У",
"Ч", "Ч",
"Я", "Я",
"Й",
"Х",
"Ц",
"Ш",
"Ю",
"Ф",
"Щ",
"Ь"
],
"letterValues": {
" ": 0,
"А": 1,
"О": 1,
"Е": 1,
"И": 1,
"Т": 1,
"Н": 1,
"П": 1,
"Р": 1,
"С": 1,
"В": 2,
"М": 2,
"Б": 2,
"Д": 2,
"К": 2,
"Л": 2,
"Г": 3,
"Ъ": 3,
"Ж": 4,
"З": 4,
"У": 5,
"Ч": 5,
"Я": 5,
"Й": 5,
"Х": 5,
"Ц": 8,
"Ш": 8,
"Ю": 8,
"Ф": 10,
"Щ": 10,
"Ь": 10
}
}

64
server/lang/br.json Normal file
View File

@ -0,0 +1,64 @@
{
"code": "br",
"name": "Breton",
"bag": [
" ", " ",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"N", "N", "N", "N", "N", "N", "N", "N", "N",
"R", "R", "R", "R", "R", "R", "R",
"O", "O", "O", "O", "O", "O",
"T", "T", "T", "T", "T",
"U", "U", "U", "U", "U",
"I", "I", "I", "I",
"L", "L", "L", "L",
"D", "D", "D", "D",
"G", "G", "G",
"S", "S", "S",
"V", "V", "V",
"H", "H",
"B", "B",
"K", "K",
"M", "M",
"Z", "Z",
"ZH", "ZH",
"CH",
"C'H",
"P",
"F",
"J",
"W",
"Y"
],
"letterValues": {
" ": 0,
"E": 1,
"A": 1,
"N": 1,
"R": 1,
"O": 1,
"T": 1,
"U": 1,
"I": 1,
"L": 1,
"D": 2,
"G": 3,
"S": 3,
"V": 3,
"H": 3,
"B": 4,
"K": 4,
"M": 4,
"Z": 4,
"ZH": 4,
"CH": 4,
"C'H": 4,
"P": 5,
"F": 10,
"J": 10,
"W": 10,
"Y": 10
}
}

58
server/lang/ca.json Normal file
View File

@ -0,0 +1,58 @@
{
"code": "ca",
"name": "Catalan",
"bag": [
" ", " ",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I",
"R", "R", "R", "R", "R", "R", "R", "R",
"S", "S", "S", "S", "S", "S", "S", "S",
"N", "N", "N", "N", "N", "N",
"O", "O", "O", "O", "O",
"T", "T", "T", "T", "T",
"L", "L", "L", "L",
"U", "U", "U", "U",
"C", "C", "C",
"D", "D", "D",
"M", "M", "M",
"B", "B",
"G", "G",
"P", "P",
"F",
"V",
"H",
"J",
"Q",
"Z",
"Ç"
],
"letterValues": {
" ": 0,
"E": 1,
"A": 1,
"I": 1,
"R": 1,
"S": 1,
"N": 1,
"O": 1,
"T": 1,
"L": 1,
"U": 1,
"C": 2,
"D": 2,
"M": 2,
"B": 3,
"G": 3,
"P": 3,
"F": 4,
"V": 4,
"H": 8,
"J": 8,
"Q": 8,
"Z": 8,
"Ç": 10
}
}

90
server/lang/cs.json Normal file
View File

@ -0,0 +1,90 @@
{
"code": "cs",
"name": "Czech",
"bag": [
" ", " ",
"O", "O", "O", "O", "O", "O",
"A", "A", "A", "A", "A",
"E", "E", "E", "E", "E",
"N", "N", "N", "N", "N",
"I", "I", "I", "I",
"S", "S", "S", "S",
"T", "T", "T", "T",
"V", "V", "V", "V",
"D", "D", "D",
"K", "K", "K",
"L", "L", "L",
"P", "P", "P",
"R", "R", "R",
"C", "C", "C",
"H", "H", "H",
"Í", "Í", "Í",
"M", "M", "M",
"U", "U", "U",
"Á", "Á",
"J", "J",
"Y", "Y",
"Z", "Z",
"B", "B",
"É", "É",
"Ě", "Ě",
"Ř", "Ř",
"Š", "Š",
"Ý", "Ý",
"Č",
"Ů",
"Ž",
"F",
"G",
"Ú",
"Ň",
"Ó",
"Ť",
"Ď",
"X"
],
"letterValues": {
" ": 0,
"O": 1,
"A": 1,
"E": 1,
"N": 1,
"I": 1,
"S": 1,
"T": 1,
"V": 1,
"D": 1,
"K": 1,
"L": 1,
"P": 1,
"R": 1,
"C": 2,
"H": 2,
"Í": 2,
"M": 2,
"U": 2,
"Á": 2,
"J": 2,
"Y": 2,
"Z": 2,
"B": 3,
"É": 3,
"Ě": 3,
"Ř": 4,
"Š": 4,
"Ý": 4,
"Č": 4,
"Ů": 4,
"Ž": 4,
"F": 5,
"G": 5,
"Ú": 5,
"Ň": 6,
"Ó": 7,
"Ť": 7,
"Ď": 8,
"X": 10
}
}

68
server/lang/cy.json Normal file
View File

@ -0,0 +1,68 @@
{
"code": "cy",
"name": "Welsh",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"E", "E", "E", "E", "E", "E", "E", "E",
"N", "N", "N", "N", "N", "N", "N", "N",
"I", "I", "I", "I", "I", "I", "I",
"R", "R", "R", "R", "R", "R", "R",
"Y", "Y", "Y", "Y", "Y", "Y", "Y",
"D", "D", "D", "D", "D", "D",
"O", "O", "O", "O", "O", "O",
"W", "W", "W", "W", "W",
"DD", "DD", "DD", "DD",
"F", "F", "F",
"G", "G", "G",
"L", "L", "L",
"U", "U", "U",
"S", "S", "S",
"B", "B",
"M", "M",
"T", "T",
"C", "C",
"FF", "FF",
"H", "H",
"TH", "TH",
"CH",
"LL",
"P",
"J",
"NG",
"RH"
],
"letterValues": {
" ": 0,
"A": 1,
"E": 1,
"N": 1,
"I": 1,
"R": 1,
"Y": 1,
"D": 1,
"O": 1,
"W": 1,
"DD": 1,
"F": 2,
"G": 2,
"L": 2,
"U": 2,
"S": 3,
"B": 3,
"M": 3,
"T": 3,
"C": 4,
"FF": 4,
"H": 4,
"TH": 4,
"CH": 5,
"LL": 5,
"P": 5,
"J": 8,
"NG": 10,
"RH": 10
}
}

66
server/lang/da.json Normal file
View File

@ -0,0 +1,66 @@
{
"code": "da",
"name": "Danish",
"bag": [
" ", " ",
"E", "E", "E", "E", "E", "E", "E", "E", "E",
"A", "A", "A", "A", "A", "A", "A",
"N", "N", "N", "N", "N", "N",
"R", "R", "R", "R", "R", "R",
"D", "D", "D", "D", "D",
"L", "L", "L", "L", "L",
"O", "O", "O", "O", "O",
"S", "S", "S", "S", "S",
"T", "T", "T", "T", "T",
"B", "B", "B", "B",
"I", "I", "I", "I",
"K", "K", "K", "K",
"F", "F", "F",
"G", "G", "G",
"M", "M", "M",
"U", "U", "U",
"V", "V", "V",
"H", "H",
"J", "J",
"P", "P",
"Y", "Y",
"Æ", "Æ",
"Ø", "Ø",
"Å", "Å",
"C", "C",
"X",
"Z"
],
"letterValues": {
" ": 0,
"E": 1,
"A": 1,
"N": 1,
"R": 1,
"D": 2,
"L": 2,
"O": 2,
"S": 2,
"T": 2,
"B": 3,
"I": 3,
"K": 3,
"F": 3,
"G": 3,
"M": 3,
"U": 3,
"V": 3,
"H": 4,
"J": 4,
"P": 4,
"Y": 4,
"Æ": 4,
"Ø": 4,
"Å": 4,
"C": 8,
"X": 8,
"Z": 8
}
}

60
server/lang/el.json Normal file
View File

@ -0,0 +1,60 @@
{
"code": "el",
"name": "Greek",
"bag": [
" ", " ",
"Α", "Α", "Α", "Α", "Α", "Α", "Α", "Α", "Α", "Α", "Α", "Α",
"Ε", "Ε", "Ε", "Ε", "Ε", "Ε", "Ε", "Ε",
"Ι", "Ι", "Ι", "Ι", "Ι", "Ι", "Ι", "Ι",
"Τ", "Τ", "Τ", "Τ", "Τ", "Τ", "Τ", "Τ",
"Η", "Η", "Η", "Η", "Η", "Η", "Η",
"Σ", "Σ", "Σ", "Σ", "Σ", "Σ", "Σ",
"Ν", "Ν", "Ν", "Ν", "Ν", "Ν",
"Ο", "Ο", "Ο", "Ο", "Ο", "Ο",
"Κ", "Κ", "Κ", "Κ",
"Π", "Π", "Π", "Π",
"Ρ", "Ρ", "Ρ", "Ρ", "Ρ",
"Υ", "Υ", "Υ", "Υ",
"Λ", "Λ", "Λ",
"Μ", "Μ", "Μ",
"Ω", "Ω", "Ω",
"Γ", "Γ",
"Δ", "Δ",
"Β",
"Φ",
"Χ",
"Ζ",
"Θ",
"Ξ",
"Ψ"
],
"letterValues": {
" ": 0,
"Α": 1,
"Ε": 1,
"Ι": 1,
"Τ": 1,
"Η": 1,
"Σ": 1,
"Ν": 1,
"Ο": 1,
"Κ": 2,
"Π": 2,
"Ρ": 2,
"Υ": 2,
"Λ": 3,
"Μ": 3,
"Ω": 3,
"Γ": 4,
"Δ": 4,
"Β": 8,
"Φ": 8,
"Χ": 8,
"Ζ": 10,
"Θ": 10,
"Ξ": 10,
"Ψ": 10
}
}

68
server/lang/eo.json Normal file
View File

@ -0,0 +1,68 @@
{
"code": "eo",
"name": "Esperanto",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A",
"E", "E", "E", "E", "E", "E", "E", "E",
"I", "I", "I", "I", "I", "I", "I", "I",
"O", "O", "O", "O", "O", "O", "O", "O",
"N", "N", "N", "N", "N", "N",
"R", "R", "R", "R", "R", "R",
"S", "S", "S", "S", "S", "S",
"L", "L", "L", "L",
"T", "T", "T", "T",
"U", "U", "U", "U",
"K", "K", "K", "K",
"M", "M", "M", "M",
"D", "D", "D",
"J", "J", "J",
"P", "P", "P",
"F", "F",
"G", "G",
"Ĝ", "Ĝ",
"V", "V",
"B", "B",
"Ĉ", "Ĉ",
"C",
"Ŝ",
"Z",
"H",
"Ŭ",
"Ĥ",
"Ĵ"
],
"letterValues": {
" ": 0,
"A": 1,
"E": 1,
"I": 1,
"O": 1,
"N": 1,
"R": 1,
"S": 1,
"L": 1,
"T": 1,
"U": 1,
"K": 2,
"M": 2,
"D": 2,
"J": 2,
"P": 2,
"F": 3,
"G": 3,
"Ĝ": 3,
"V": 3,
"B": 4,
"Ĉ": 4,
"C": 4,
"Ŝ": 4,
"Z": 5,
"H": 8,
"Ŭ": 8,
"Ĥ": 10,
"Ĵ": 10
}
}

View File

@ -35,34 +35,34 @@
],
"letterValues": {
" ": 0,
"A": 1,
"E": 1,
"O": 1,
"I": 1,
"S": 1,
"N": 1,
"R": 1,
"U": 1,
"L": 1,
"T": 1,
"D": 2,
"G": 2,
"C": 3,
"B": 3,
"M": 3,
"P": 3,
"H": 4,
"F": 4,
"V": 4,
"Y": 4,
" ": 0,
"A": 1,
"E": 1,
"O": 1,
"I": 1,
"S": 1,
"N": 1,
"R": 1,
"U": 1,
"L": 1,
"T": 1,
"D": 2,
"G": 2,
"C": 3,
"B": 3,
"M": 3,
"P": 3,
"H": 4,
"F": 4,
"V": 4,
"Y": 4,
"CH": 5,
"Q": 5,
"J": 8,
"Q": 5,
"J": 8,
"LL": 8,
"Ñ": 8,
"Ñ": 8,
"RR": 8,
"X": 8,
"Z": 10
"X": 8,
"Z": 10
}
}

66
server/lang/et.json Normal file
View File

@ -0,0 +1,66 @@
{
"code": "et",
"name": "Estonian",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"E", "E", "E", "E", "E", "E", "E", "E", "E",
"I", "I", "I", "I", "I", "I", "I", "I", "I",
"S", "S", "S", "S", "S", "S", "S", "S",
"T", "T", "T", "T", "T", "T", "T",
"K", "K", "K", "K", "K",
"L", "L", "L", "L", "L",
"O", "O", "O", "O", "O",
"U", "U", "U", "U", "U",
"D", "D", "D", "D",
"M", "M", "M", "M",
"N", "N", "N", "N",
"R", "R",
"G", "G",
"V", "V",
"B",
"H", "H",
"J", "J",
"Õ", "Õ",
"P", "P",
"Ä", "Ä",
"Ü", "Ü",
"Ö", "Ö",
"F",
"Š",
"Z",
"Ž"
],
"letterValues": {
" ": 0,
"A": 1,
"E": 1,
"I": 1,
"S": 1,
"T": 1,
"K": 1,
"L": 1,
"O": 1,
"U": 1,
"D": 2,
"M": 2,
"N": 2,
"R": 2,
"G": 3,
"V": 3,
"B": 4,
"H": 4,
"J": 4,
"Õ": 4,
"P": 4,
"Ä": 5,
"Ü": 5,
"Ö": 6,
"F": 8,
"Š": 10,
"Z": 10,
"Ž": 10
}
}

62
server/lang/eu.json Normal file
View File

@ -0,0 +1,62 @@
{
"code": "eu",
"name": "Basque",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"I", "I", "I", "I", "I", "I", "I", "I", "I",
"N", "N", "N", "N", "N", "N", "N", "N",
"O", "O", "O", "O", "O", "O",
"T", "T", "T", "T", "T", "T",
"U", "U", "U", "U", "U", "U",
"K", "K", "K", "K", "K",
"R", "R", "R", "R", "R",
"D", "D", "D", "D",
"B", "B", "B",
"Z", "Z", "Z",
"G", "G",
"H", "H",
"L", "L",
"S", "S",
"J",
"M",
"P",
"RR",
"TS",
"TX",
"TZ",
"F",
"X"
],
"letterValues": {
" ": 0,
"A": 1,
"E": 1,
"I": 1,
"N": 1,
"O": 1,
"T": 1,
"U": 1,
"K": 2,
"R": 2,
"D": 3,
"B": 4,
"Z": 4,
"G": 5,
"H": 5,
"L": 5,
"S": 5,
"J": 8,
"M": 8,
"P": 8,
"RR": 8,
"TS": 8,
"TX": 8,
"TZ": 8,
"F": 10,
"X": 10
}
}

60
server/lang/fi.json Normal file
View File

@ -0,0 +1,60 @@
{
"code": "fi",
"name": "Finnish",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I", "I", "I",
"N", "N", "N", "N", "N", "N", "N", "N", "N",
"T", "T", "T", "T", "T", "T", "T", "T", "T",
"E", "E", "E", "E", "E", "E", "E", "E",
"S", "S", "S", "S", "S", "S", "S",
"K", "K", "K", "K", "K",
"L", "L", "L", "L", "L",
"O", "O", "O", "O", "O",
"Ä", "Ä", "Ä", "Ä", "Ä",
"U", "U", "U", "U",
"M", "M", "M",
"H", "H",
"J", "J",
"P", "P",
"R", "R",
"V", "V",
"Y", "Y",
"D",
"Ö",
"B",
"F",
"G",
"C"
],
"letterValues": {
" ": 0,
"A": 1,
"I": 1,
"N": 1,
"T": 1,
"E": 1,
"S": 1,
"K": 2,
"L": 2,
"O": 2,
"Ä": 2,
"U": 3,
"M": 3,
"H": 4,
"J": 4,
"P": 4,
"R": 4,
"V": 4,
"Y": 4,
"D": 7,
"Ö": 7,
"B": 8,
"F": 8,
"G": 8,
"C": 10
}
}

58
server/lang/ga.json Normal file
View File

@ -0,0 +1,58 @@
{
"code": "ga",
"name": "Irish",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"H", "H", "H", "H", "H", "H", "H", "H", "H", "H",
"I", "I", "I", "I", "I", "I", "I", "I", "I", "I",
"N", "N", "N", "N", "N", "N", "N",
"R", "R", "R", "R", "R", "R", "R",
"E", "E", "E", "E", "E", "E",
"S", "S", "S", "S", "S", "S",
"C", "C", "C", "C",
"D", "D", "D", "D",
"L", "L", "L", "L",
"O", "O", "O", "O",
"T", "T", "T", "T",
"G", "G", "G",
"U", "U", "U",
"F", "F",
"M", "M",
"Á", "Á",
"Í", "Í",
"É",
"Ó",
"Ú",
"B",
"P"
],
"letterValues": {
" ": 0,
"A": 1,
"H": 1,
"I": 1,
"N": 1,
"R": 1,
"E": 1,
"S": 1,
"C": 2,
"D": 2,
"L": 2,
"O": 2,
"T": 2,
"G": 2,
"U": 2,
"F": 4,
"M": 4,
"Á": 4,
"Í": 4,
"É": 8,
"Ó": 8,
"Ú": 8,
"B": 10,
"P": 10
}
}

56
server/lang/he.json Normal file
View File

@ -0,0 +1,56 @@
{
"code": "he",
"name": "Hebrew",
"bag": [
" ", " ",
"ו", "ו", "ו", "ו", "ו", "ו", "ו", "ו", "ו", "ו", "ו", "ו",
"י", "י", "י", "י", "י", "י", "י", "י", "י", "י",
"ת", "ת", "ת", "ת", "ת", "ת", "ת", "ת", "ת",
"ה", "ה", "ה", "ה", "ה", "ה", "ה", "ה",
"ר", "ר", "ר", "ר", "ר", "ר", "ר", "ר",
"א", "א", "א", "א", "א", "א",
"ל", "ל", "ל", "ל", "ל", "ל",
"מ", "מ", "מ", "מ", "מ", "מ",
"ש", "ש", "ש", "ש", "ש", "ש",
"ד", "ד", "ד", "ד",
"נ", "נ", "נ", "נ",
"ב", "ב", "ב", "ב",
"ח", "ח", "ח",
"פ", "פ", "פ",
"ק", "ק", "ק",
"ג", "ג",
"כ", "כ",
"ע", "ע",
"ז",
"ט",
"ס",
"צ"
],
"letterValues": {
" ": 0,
"ו": 1,
"י": 1,
"ת": 1,
"ה": 1,
"ר": 1,
"א": 2,
"ל": 2,
"מ": 2,
"ש": 2,
"ד": 3,
"נ": 3,
"ב": 4,
"ח": 4,
"פ": 4,
"ק": 4,
"ג": 5,
"כ": 5,
"ע": 5,
"ז": 8,
"ט": 8,
"ס": 8,
"צ": 8
}
}

72
server/lang/hr.json Normal file
View File

@ -0,0 +1,72 @@
{
"code": "hr",
"name": "Croatian",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I", "I", "I",
"E", "E", "E", "E", "E", "E", "E", "E", "E",
"O", "O", "O", "O", "O", "O", "O", "O", "O",
"N", "N", "N", "N", "N", "N",
"R", "R", "R", "R", "R",
"S", "S", "S", "S", "S",
"T", "T", "T", "T", "T",
"J", "J", "J", "J",
"U", "U", "U", "U",
"K", "K", "K",
"M", "M", "M",
"P", "P", "P",
"V", "V", "V",
"D", "D", "D",
"G", "G",
"L", "L",
"Z", "Z",
"B",
"Č",
"C",
"H",
"LJ",
"NJ",
"Š",
"Ž",
"Ć",
"F",
"DŽ",
"Đ"
],
"letterValues": {
" ": 0,
"A": 1,
"I": 1,
"E": 1,
"O": 1,
"N": 1,
"R": 1,
"S": 1,
"T": 1,
"J": 1,
"U": 1,
"K": 2,
"M": 2,
"P": 2,
"V": 2,
"D": 3,
"G": 3,
"L": 3,
"Z": 3,
"B": 3,
"Č": 3,
"C": 4,
"H": 4,
"LJ": 4,
"NJ": 4,
"Š": 4,
"Ž": 4,
"Ć": 5,
"F": 8,
"DŽ": 10,
"Đ": 10
}
}

88
server/lang/hu.json Normal file
View File

@ -0,0 +1,88 @@
{
"code": "hu",
"name": "Hungarian",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A",
"E", "E", "E", "E", "E", "E",
"K", "K", "K", "K", "K", "K",
"T", "T", "T", "T", "T",
"Á", "Á", "Á", "Á",
"L", "L", "L", "L",
"N", "N", "N", "N",
"R", "R", "R", "R",
"I", "I", "I",
"M", "M", "M",
"O", "O", "O",
"S", "S", "S",
"B", "B", "B",
"D", "D", "D",
"G", "G", "G",
"Ó", "Ó", "Ó",
"É", "É", "É",
"H", "H",
"SZ", "SZ",
"V", "V",
"F", "F",
"GY", "GY",
"J", "J",
"Ö", "Ö",
"P", "P",
"U", "U",
"Ü", "Ü",
"Z", "Z",
"C",
"Í",
"NY",
"CS",
"Ő",
"Ú",
"Ű",
"LY",
"ZS",
"TY"
],
"letterValues": {
" ": 0,
"A": 1,
"E": 1,
"K": 1,
"T": 1,
"Á": 1,
"L": 1,
"N": 1,
"R": 1,
"I": 1,
"M": 1,
"O": 1,
"S": 1,
"B": 2,
"D": 2,
"G": 2,
"Ó": 2,
"É": 3,
"H": 3,
"SZ": 3,
"V": 3,
"F": 4,
"GY": 4,
"J": 4,
"Ö": 4,
"P": 4,
"U": 4,
"Ü": 4,
"Z": 4,
"C": 5,
"Í": 5,
"NY": 5,
"CS": 7,
"Ő": 7,
"Ú": 7,
"Ű": 7,
"LY": 8,
"ZS": 8,
"TY": 10
}
}

88
server/lang/hy.json Normal file
View File

@ -0,0 +1,88 @@
{
"code": "hy",
"name": "Armenian",
"bag": [
" ", " ", " ",
"Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա", "Ա",
"Ե", "Ե", "Ե", "Ե", "Ե", "Ե", "Ե", "Ե", "Ե", "Ե",
"Ի", "Ի", "Ի", "Ի", "Ի", "Ի", "Ի", "Ի", "Ի", "Ի",
"Կ", "Կ", "Կ", "Կ", "Կ", "Կ", "Կ",
"Ն", "Ն", "Ն", "Ն", "Ն", "Ն", "Ն",
"Ո", "Ո", "Ո", "Ո", "Ո", "Ո", "Ո", "Ո",
"Ս", "Ս", "Ս", "Ս", "Ս", "Ս",
"Է", "Է", "Է", "Է",
"Հ", "Հ", "Հ", "Հ",
"Մ", "Մ", "Մ", "Մ",
"Յ", "Յ", "Յ", "Յ",
"Պ", "Պ", "Պ", "Պ",
"Տ", "Տ", "Տ", "Տ", "Տ",
"Ր", "Ր", "Ր", "Ր", "Ր",
"Ւ", "Ւ", "Ւ", "Ւ", "Ւ",
"Բ", "Բ", "Բ",
"Գ", "Գ", "Գ",
"Դ", "Դ", "Դ",
"Լ", "Լ", "Լ", "Լ",
"Վ", "Վ",
"Ք", "Ք", "Ք",
"Խ", "Խ",
"Շ", "Շ",
"Ռ", "Ռ",
"Թ", "Թ",
"Ծ", "Ծ",
"Ղ", "Ղ",
"Ց", "Ց",
"Զ",
"Ճ",
"Չ",
"Ջ",
"Ժ",
"Ձ",
"Փ",
"Օ",
"Ը",
"Ֆ"
],
"letterValues": {
" ": 0,
"Ա": 1,
"Ե": 1,
"Ի": 1,
"Կ": 1,
"Ն": 1,
"Ո": 1,
"Ս": 1,
"Է": 2,
"Հ": 2,
"Մ": 2,
"Յ": 2,
"Պ": 2,
"Տ": 2,
"Ր": 2,
"Ւ": 2,
"Բ": 3,
"Գ": 3,
"Դ": 3,
"Լ": 3,
"Վ": 3,
"Ք": 3,
"Խ": 4,
"Շ": 4,
"Ռ": 4,
"Թ": 5,
"Ծ": 5,
"Ղ": 5,
"Ց": 5,
"Զ": 6,
"Ճ": 6,
"Չ": 6,
"Ջ": 6,
"Ժ": 8,
"Ձ": 8,
"Փ": 8,
"Օ": 8,
"Ը": 10,
"Ֆ": 10
}
}

76
server/lang/is.json Normal file
View File

@ -0,0 +1,76 @@
{
"code": "is",
"name": "Icelandic",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I",
"N", "N", "N", "N", "N", "N", "N", "N",
"R", "R", "R", "R", "R", "R", "R",
"E", "E", "E", "E", "E", "E",
"S", "S", "S", "S", "S", "S",
"U", "U", "U", "U", "U", "U",
"T", "T", "T", "T", "T",
"Ð", "Ð", "Ð", "Ð", "Ð",
"G", "G", "G", "G",
"K", "K", "K",
"L", "L", "L",
"M", "M", "M",
"F", "F", "F",
"O", "O", "O",
"H", "H",
"V", "V",
"Á", "Á",
"D", "D",
"Í", "Í",
"Þ",
"J",
"Æ",
"B",
"É",
"Ó",
"Ö",
"Y",
"P",
"Ú",
"Ý",
"X"
],
"letterValues": {
" ": 0,
"A": 1,
"I": 1,
"N": 1,
"R": 1,
"E": 1,
"S": 1,
"U": 1,
"T": 1,
"Ð": 2,
"G": 2,
"K": 2,
"L": 2,
"M": 2,
"F": 3,
"O": 3,
"H": 3,
"V": 3,
"Á": 4,
"D": 4,
"Í": 4,
"Þ": 4,
"J": 5,
"Æ": 5,
"B": 6,
"É": 6,
"Ó": 6,
"Ö": 7,
"Y": 7,
"P": 8,
"Ú": 8,
"Ý": 9,
"X": 10
}
}

54
server/lang/it.json Normal file
View File

@ -0,0 +1,54 @@
{
"code": "it",
"name": "Italian",
"bag": [
" ", " ",
"O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I", "I", "I", "I", "I",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"C", "C", "C", "C", "C", "C",
"R", "R", "R", "R", "R", "R",
"S", "S", "S", "S", "S", "S",
"T", "T", "T", "T", "T", "T",
"L", "L", "L", "L", "L",
"M", "M", "M", "M", "M",
"N", "N", "N", "N", "N",
"U", "U", "U", "U", "U",
"B", "B", "B",
"D", "D", "D",
"F", "F", "F",
"P", "P", "P",
"V", "V", "V",
"G", "G",
"H", "H",
"Z", "Z",
"Q"
],
"letterValues": {
" ": 0,
"O": 1,
"A": 1,
"I": 1,
"E": 1,
"C": 2,
"R": 2,
"S": 2,
"T": 2,
"L": 3,
"M": 3,
"N": 3,
"U": 3,
"B": 5,
"D": 5,
"F": 5,
"P": 5,
"V": 5,
"G": 8,
"H": 8,
"Z": 8,
"Q": 10
}
}

52
server/lang/la.json Normal file
View File

@ -0,0 +1,52 @@
{
"code": "la",
"name": "Latin",
"bag": [
" ", " ",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I", "I",
"V", "V", "V", "V", "V", "V", "V", "V", "V",
"S", "S", "S", "S", "S", "S", "S", "S",
"T", "T", "T", "T", "T", "T", "T", "T",
"R", "R", "R", "R", "R", "R", "R",
"O", "O", "O", "O", "O",
"C", "C", "C", "C",
"M", "M", "M", "M",
"N", "N", "N", "N",
"D", "D", "D",
"L", "L", "L",
"Q", "Q", "Q",
"B", "B",
"G", "G",
"P", "P",
"X", "X",
"F",
"H"
],
"letterValues": {
" ": 0,
"E": 1,
"A": 1,
"I": 1,
"V": 1,
"S": 1,
"T": 1,
"R": 1,
"O": 1,
"C": 2,
"M": 2,
"N": 2,
"D": 2,
"L": 2,
"Q": 3,
"B": 4,
"G": 4,
"P": 4,
"X": 4,
"F": 8,
"H": 8
}
}

76
server/lang/lt.json Normal file
View File

@ -0,0 +1,76 @@
{
"code": "lt",
"name": "Lithuanian",
"bag": [
" ", " ",
"I", "I", "I", "I", "I", "I", "I", "I", "I", "I", "I",
"A", "A", "A", "A", "A", "A", "A", "A", "A",
"R", "R", "R", "R", "R", "R", "R", "R", "R",
"E", "E", "E", "E", "E", "E",
"L", "L", "L", "L", "L", "L",
"S", "S", "S", "S", "S", "S",
"O", "O", "O", "O", "O",
"T", "T", "T", "T", "T",
"U", "U", "U", "U", "U",
"N", "N", "N", "N",
"Ą",
"K", "K", "K", "K",
"D", "D", "D",
"M", "M", "M",
"P", "P", "P",
"B", "B",
"G", "G",
"Ę",
"Ė", "Ė",
"Š", "Š",
"Ų",
"J", "J",
"Į",
"V",
"Ž",
"Ū",
"Z",
"Y",
"C",
"Č",
"F",
"H"
],
"letterValues": {
" ": 0,
"I": 1,
"A": 1,
"R": 1,
"E": 1,
"L": 1,
"S": 1,
"O": 1,
"T": 1,
"U": 1,
"N": 1,
"Ą": 1,
"K": 2,
"D": 2,
"M": 2,
"P": 2,
"B": 2,
"G": 2,
"Ę": 2,
"Ė": 3,
"Š": 3,
"Ų": 3,
"J": 4,
"Į": 4,
"V": 4,
"Ž": 4,
"Ū": 5,
"Z": 5,
"Y": 6,
"C": 7,
"Č": 7,
"F": 10,
"H": 10
}
}

78
server/lang/lv.json Normal file
View File

@ -0,0 +1,78 @@
{
"code": "lv",
"name": "Latvian",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I", "I",
"S", "S", "S", "S", "S", "S", "S", "S",
"E", "E", "E", "E", "E", "E",
"T", "T", "T", "T", "T", "T",
"R", "R", "R", "R", "R",
"U", "U", "U", "U", "U",
"Ā", "Ā", "Ā", "Ā",
"K", "K", "K", "K",
"M", "M", "M", "M",
"N", "N", "N", "N",
"L", "L", "L",
"P", "P", "P",
"D", "D", "D",
"O", "O", "O",
"V", "V", "V",
"Z", "Z",
"Ē", "Ē",
"Ī", "Ī",
"J", "J",
"B",
"C",
"G",
"Ņ",
"Š",
"Ū",
"Ļ",
"Ž",
"Č",
"F",
"Ģ",
"H",
"Ķ"
],
"letterValues": {
" ": 0,
"A": 1,
"I": 1,
"S": 1,
"E": 1,
"T": 1,
"R": 1,
"U": 1,
"Ā": 2,
"K": 2,
"M": 2,
"N": 2,
"L": 2,
"P": 2,
"D": 3,
"O": 3,
"V": 3,
"Z": 3,
"Ē": 4,
"Ī": 4,
"J": 4,
"B": 5,
"C": 5,
"G": 5,
"Ņ": 6,
"Š": 6,
"Ū": 6,
"Ļ": 8,
"Ž": 8,
"Č": 10,
"F": 10,
"Ģ": 10,
"H": 10,
"Ķ": 10
}
}

58
server/lang/ms.json Normal file
View File

@ -0,0 +1,58 @@
{
"code": "ms",
"name": "Malay",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"N", "N", "N", "N", "N", "N", "N", "N",
"E", "E", "E", "E", "E", "E", "E",
"I", "I", "I", "I", "I", "I", "I",
"K", "K", "K", "K", "K", "K",
"U", "U", "U", "U", "U", "U",
"M", "M", "M", "M", "M",
"R", "R", "R", "R", "R",
"T", "T", "T", "T", "T",
"L", "L", "L", "L",
"S", "S", "S", "S",
"G", "G", "G", "G",
"B", "B", "B",
"D", "D", "D",
"H", "H",
"O", "O",
"P", "P",
"J",
"Y",
"C",
"W",
"F",
"Z"
],
"letterValues": {
" ": 0,
"A": 1,
"N": 1,
"E": 1,
"I": 1,
"K": 1,
"U": 1,
"M": 1,
"R": 1,
"T": 1,
"L": 2,
"S": 2,
"G": 3,
"B": 3,
"D": 3,
"H": 4,
"O": 4,
"P": 4,
"J": 5,
"Y": 5,
"C": 8,
"W": 8,
"F": 10,
"Z": 10
}
}

66
server/lang/nl.json Normal file
View File

@ -0,0 +1,66 @@
{
"code": "nl",
"name": "Dutch",
"bag": [
" ", " ",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"N", "N", "N", "N", "N", "N", "N", "N", "N", "N",
"A", "A", "A", "A", "A", "A",
"O", "O", "O", "O", "O", "O",
"I", "I", "I", "I",
"D", "D", "D", "D", "D",
"R", "R", "R", "R", "R",
"T", "T", "T", "T", "T",
"S", "S", "S", "S",
"G", "G", "G",
"K", "K", "K",
"L", "L", "L",
"M", "M", "M",
"B", "B",
"P", "P",
"U", "U", "U",
"H", "H",
"J", "J",
"V", "V",
"Z", "Z",
"IJ", "IJ",
"F",
"C", "C",
"W", "W",
"X",
"Y",
"Q"
],
"letterValues": {
" ": 0,
"E": 1,
"N": 1,
"A": 1,
"O": 1,
"I": 1,
"D": 2,
"R": 2,
"T": 2,
"S": 2,
"G": 3,
"K": 3,
"L": 3,
"M": 3,
"B": 3,
"P": 3,
"U": 4,
"H": 4,
"J": 4,
"V": 4,
"Z": 4,
"IJ": 4,
"F": 4,
"C": 5,
"W": 5,
"X": 8,
"Y": 8,
"Q": 10
}
}

64
server/lang/no.json Normal file
View File

@ -0,0 +1,64 @@
{
"code": "no",
"name": "Norwegian",
"bag": [
" ", " ",
"E", "E", "E", "E", "E", "E", "E", "E", "E",
"A", "A", "A", "A", "A", "A", "A",
"N", "N", "N", "N", "N", "N",
"R", "R", "R", "R", "R", "R",
"S", "S", "S", "S", "S", "S",
"T", "T", "T", "T", "T", "T",
"D", "D", "D", "D", "D",
"I", "I", "I", "I", "I",
"L", "L", "L", "L", "L",
"F", "F", "F", "F",
"G", "G", "G", "G",
"K", "K", "K", "K",
"O", "O", "O", "O",
"M", "M", "M",
"H", "H", "H",
"B", "B", "B",
"U", "U", "U",
"V", "V", "V",
"J", "J",
"P", "P",
"Å", "Å",
"Ø", "Ø",
"Y",
"Æ",
"W",
"C"
],
"letterValues": {
" ": 0,
"E": 1,
"A": 1,
"N": 1,
"R": 1,
"S": 1,
"T": 1,
"D": 1,
"I": 1,
"L": 1,
"F": 2,
"G": 2,
"K": 2,
"O": 2,
"M": 2,
"H": 3,
"B": 4,
"U": 4,
"V": 4,
"J": 4,
"P": 4,
"Å": 4,
"Ø": 5,
"Y": 6,
"Æ": 6,
"W": 8,
"C": 10
}
}

76
server/lang/pl.json Normal file
View File

@ -0,0 +1,76 @@
{
"code": "pl",
"name": "Polish",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I",
"E", "E", "E", "E", "E", "E", "E",
"O", "O", "O", "O", "O", "O",
"N", "N", "N", "N", "N",
"Z", "Z", "Z", "Z", "Z",
"R", "R", "R", "R",
"S", "S", "S", "S",
"W", "W", "W", "W",
"Y", "Y", "Y", "Y",
"C", "C", "C",
"D", "D", "D",
"K", "K", "K",
"L", "L", "L",
"M", "M", "M",
"P", "P", "P",
"T", "T", "T",
"B", "B",
"G", "G",
"H", "H",
"J", "J",
"Ł", "Ł",
"U", "U",
"Ą",
"Ę",
"F",
"Ó",
"Ś",
"Ż",
"Ć",
"Ń",
"Ź"
],
"letterValues": {
" ": 0,
"A": 1,
"I": 1,
"E": 1,
"O": 1,
"N": 1,
"Z": 1,
"R": 1,
"S": 1,
"W": 1,
"Y": 2,
"C": 2,
"D": 2,
"K": 2,
"L": 2,
"M": 2,
"P": 2,
"T": 2,
"B": 3,
"G": 3,
"H": 3,
"J": 3,
"Ł": 3,
"U": 3,
"Ą": 5,
"Ę": 5,
"F": 5,
"Ó": 5,
"Ś": 5,
"Ż": 5,
"Ć": 6,
"Ń": 7,
"Ź": 9
}
}

78
server/lang/ru.json Normal file
View File

@ -0,0 +1,78 @@
{
"code": "ru",
"name": "Russian",
"bag": [
" ", " ",
"О", "О", "О", "О", "О", "О", "О", "О", "О", "О", "О",
"Е", "Е", "Е", "Е", "Е", "Е", "Е", "Е", "Е", "Е",
"И", "И", "И", "И", "И", "И", "И", "И", "И", "И",
"А", "А", "А", "А", "А", "А", "А", "А", "А",
"Н", "Н", "Н", "Н", "Н", "Н",
"Р", "Р", "Р", "Р", "Р", "Р",
"Т", "Т", "Т", "Т", "Т", "Т",
"В", "В", "В", "В", "В",
"С", "С", "С", "С", "С",
"Д", "Д", "Д", "Д",
"К", "К", "К", "К",
"Л", "Л", "Л", "Л",
"М", "М", "М", "М",
"П", "П", "П", "П",
"У", "У", "У", "У",
"Я", "Я", "Я", "Я",
"Б", "Б", "Б",
"Г", "Г", "Г",
"Ë", "Ë", "Ë",
"Ь", "Ь",
"Й", "Й",
"Ы", "Ы",
"Ж", "Ж",
"З", "З",
"Х",
"Ц",
"Ч",
"Ш",
"Э",
"Ю",
"Ф",
"Щ",
"Ъ"
],
"letterValues": {
" ": 0,
"О": 1,
"Е": 1,
"И": 1,
"А": 1,
"Н": 1,
"Р": 1,
"Т": 1,
"В": 1,
"С": 1,
"Д": 2,
"К": 2,
"Л": 2,
"М": 2,
"П": 2,
"У": 2,
"Я": 3,
"Б": 3,
"Г": 3,
"Ë": 3,
"Ь": 3,
"Й": 4,
"Ы": 4,
"Ж": 5,
"З": 5,
"Х": 5,
"Ц": 5,
"Ч": 5,
"Ш": 8,
"Э": 8,
"Ю": 8,
"Ф": 10,
"Щ": 10,
"Ъ": 10
}
}

94
server/lang/sk.json Normal file
View File

@ -0,0 +1,94 @@
{
"code": "sk",
"name": "Slovak",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A",
"O", "O", "O", "O", "O", "O", "O", "O", "O",
"E", "E", "E", "E", "E", "E", "E", "E",
"I", "I", "I", "I", "I",
"N", "N", "N", "N", "N",
"R", "R", "R", "R",
"S", "S", "S", "S",
"T", "T", "T", "T",
"V", "V", "V", "V",
"M", "M", "M", "M",
"D", "D", "D",
"K", "K", "K",
"L", "L", "L",
"P", "P", "P",
"J", "J",
"U", "U",
"B", "B",
"H",
"Y",
"Z",
"Á",
"C",
"Č",
"Ž",
"Š",
"Í",
"Ý",
"Ľ",
"Ť",
"É",
"Ú",
"Ď",
"F",
"G",
"Ň",
"Ô",
"Ĺ",
"Ŕ",
"X",
"Ä",
"Ó"
],
"letterValues": {
" ": 0,
"A": 1,
"O": 1,
"E": 1,
"I": 1,
"N": 1,
"R": 1,
"S": 1,
"T": 1,
"V": 1,
"M": 2,
"D": 2,
"K": 2,
"L": 2,
"P": 2,
"J": 3,
"U": 3,
"B": 4,
"H": 4,
"Y": 4,
"Z": 4,
"Á": 4,
"C": 4,
"Č": 5,
"Ž": 5,
"Š": 5,
"Í": 5,
"Ý": 5,
"Ľ": 7,
"Ť": 7,
"É": 7,
"Ú": 7,
"Ď": 8,
"F": 8,
"G": 8,
"Ň": 8,
"Ô": 8,
"Ĺ": 10,
"Ŕ": 10,
"X": 10,
"Ä": 10,
"Ó": 10
}
}

62
server/lang/sl.json Normal file
View File

@ -0,0 +1,62 @@
{
"code": "sl",
"name": "Slovenian",
"bag": [
" ", " ",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"I", "I", "I", "I", "I", "I", "I", "I", "I",
"O", "O", "O", "O", "O", "O", "O", "O",
"N", "N", "N", "N", "N", "N", "N",
"R", "R", "R", "R", "R", "R",
"S", "S", "S", "S", "S", "S",
"J", "J", "J", "J",
"L", "L", "L", "L",
"T", "T", "T", "T",
"D", "D", "D", "D",
"V", "V", "V", "V",
"K", "K", "K",
"M", "M",
"P", "P",
"U", "U",
"B", "B",
"G", "G",
"Z", "Z",
"Č",
"H",
"Š",
"C",
"F",
"Ž"
],
"letterValues": {
" ": 0,
"E": 1,
"A": 1,
"I": 1,
"O": 1,
"N": 1,
"R": 1,
"S": 1,
"J": 1,
"L": 1,
"T": 1,
"D": 2,
"V": 2,
"K": 3,
"M": 3,
"P": 3,
"U": 3,
"B": 4,
"G": 4,
"Z": 4,
"Č": 5,
"H": 5,
"Š": 6,
"C": 8,
"F": 10,
"Ž": 10
}
}

66
server/lang/sv.json Normal file
View File

@ -0,0 +1,66 @@
{
"code": "sv",
"name": "Swedish",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A",
"R", "R", "R", "R", "R", "R", "R", "R",
"S", "S", "S", "S", "S", "S", "S", "S",
"T", "T", "T", "T", "T", "T", "T", "T",
"E", "E", "E", "E", "E", "E", "E",
"N", "N", "N", "N", "N", "N",
"D", "D", "D", "D", "D",
"I", "I", "I", "I", "I",
"L", "L", "L", "L", "L",
"O", "O", "O", "O", "O",
"G", "G", "G",
"K", "K", "K",
"M", "M", "M",
"H", "H",
"Ä", "Ä",
"F", "F",
"V", "V",
"U", "U", "U",
"B", "B",
"Ö", "Ö",
"P", "P",
"Å", "Å",
"J",
"Y",
"C",
"X",
"Z"
],
"letterValues": {
" ": 0,
"A": 1,
"R": 1,
"S": 1,
"T": 1,
"E": 1,
"N": 1,
"D": 1,
"I": 1,
"L": 1,
"O": 2,
"G": 2,
"K": 2,
"M": 2,
"H": 2,
"Ä": 3,
"F": 3,
"V": 3,
"U": 4,
"B": 4,
"Ö": 4,
"P": 4,
"Å": 4,
"J": 7,
"Y": 7,
"C": 8,
"X": 8,
"Z": 10
}
}

68
server/lang/tr.json Normal file
View File

@ -0,0 +1,68 @@
{
"code": "tr",
"name": "Turkish",
"bag": [
" ", " ",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"E", "E", "E", "E", "E", "E", "E", "E",
"K", "K", "K", "K", "K", "K", "K",
"L", "L", "L", "L", "L", "L", "L",
"R", "R", "R", "R", "R", "R",
"N", "N", "N", "N", "N",
"T", "T", "T", "T", "T",
"I", "I", "I", "I",
"M", "M", "M", "M",
"O", "O", "O",
"S", "S", "S",
"U", "U", "U",
"B", "B",
"D", "D",
"Y", "Y",
"Ü", "Ü",
"C", "C",
"Ş", "Ş",
"Z", "Z",
"Ç", "Ç",
"H",
"P",
"G",
"F",
"V",
"Ö",
"Ğ",
"J"
],
"letterValues": {
" ": 0,
"A": 1,
"E": 1,
"K": 1,
"L": 1,
"R": 1,
"N": 1,
"T": 1,
"I": 2,
"M": 2,
"O": 2,
"S": 2,
"U": 2,
"B": 3,
"D": 3,
"Y": 3,
"Ü": 3,
"C": 4,
"Ş": 4,
"Z": 4,
"Ç": 4,
"H": 5,
"P": 5,
"G": 5,
"F": 7,
"V": 7,
"Ö": 7,
"Ğ": 8,
"J": 10
}
}

80
server/lang/uk.json Normal file
View File

@ -0,0 +1,80 @@
{
"code": "uk",
"name": "Ukrainian",
"bag": [
" ", " ",
"О", "О", "О", "О", "О", "О", "О", "О", "О",
"А", "А", "А", "А", "А", "А", "А", "А",
"И", "И", "И", "И", "И", "И",
"Н", "Н", "Н", "Н", "Н", "Н",
"В", "В", "В", "В", "В",
"Е", "Е", "Е", "Е", "Е",
"І", "І", "І", "І", "І",
"Т", "Т", "Т", "Т", "Т",
"К", "К", "К", "К",
"Р", "Р", "Р", "Р",
"С", "С", "С", "С",
"Д", "Д", "Д",
"Л", "Л", "Л",
"М", "М", "М",
"У", "У", "У",
"П", "П", "П",
"З", "З",
"Я", "Я",
"Ь", "Ь",
"Б", "Б",
"Г", "Г",
"Ч", "Ч",
"Х",
"Є",
"Ї",
"Й",
"Ж",
"Ц",
"Ш",
"Ю",
"Ґ",
"Ф",
"Щ",
"'"
],
"letterValues": {
" ": 0,
"О": 1,
"А": 1,
"И": 1,
"Н": 1,
"В": 1,
"Е": 1,
"І": 1,
"Т": 1,
"К": 2,
"Р": 2,
"С": 2,
"Д": 3,
"Л": 3,
"М": 3,
"У": 3,
"П": 4,
"З": 4,
"Я": 4,
"Ь": 4,
"Б": 5,
"Г": 5,
"Ч": 5,
"Х": 5,
"Є": 8,
"Ї": 8,
"Й": 8,
"Ж": 8,
"Ц": 8,
"Ш": 8,
"Ю": 8,
"Ґ": 10,
"Ф": 10,
"Щ": 10,
"'": 10
}
}

64
server/lang/xk.json Normal file
View File

@ -0,0 +1,64 @@
{
"code": "xk",
"name": "Klingon",
"bag": [
" ", " ",
"ʼ", "ʼ", "ʼ", "ʼ", "ʼ", "ʼ", "ʼ", "ʼ", "ʼ", "ʼ",
"a", "a", "a", "a", "a", "a", "a", "a", "a", "a",
"e", "e", "e", "e", "e", "e", "e", "e",
"ɪ", "ɪ", "ɪ", "ɪ", "ɪ", "ɪ", "ɪ", "ɪ",
"o", "o", "o", "o", "o", "o",
"u", "u", "u", "u", "u", "u",
"H", "H", "H", "H", "H",
"j", "j", "j", "j", "j",
"m", "m", "m", "m", "m",
"D", "D", "D", "D",
"v", "v", "v", "v",
"l", "l", "l",
"b", "b",
"ch", "ch",
"gh", "gh",
"n", "n",
"q", "q",
"S", "S",
"p", "p",
"t", "t",
"w", "w",
"y", "y",
"Q",
"r",
"tlh",
"ng"
],
"letterValues": {
" ": 0,
"ʼ": 1,
"a": 1,
"e": 1,
"ɪ": 1,
"o": 1,
"u": 1,
"H": 1,
"j": 2,
"m": 2,
"D": 2,
"v": 2,
"l": 3,
"b": 3,
"ch": 3,
"gh": 3,
"n": 3,
"q": 3,
"S": 3,
"p": 4,
"t": 4,
"w": 5,
"y": 5,
"Q": 6,
"r": 6,
"tlh": 8,
"ng": 10
}
}

View File

@ -28,12 +28,15 @@
"use strict";
const port = parseInt(process.env.TRIVABBLE_PORT || "3000");
const host = process.env.TRIVABBLE_HOST || "localhost"
const host = process.env.TRIVABBLE_HOST || "localhost";
const disableCSP = process.env.DISABLE_CSP || false;
const SAVE_TIMEOUT = 5000;
const KEEP_ALIVE = 30000;
const GAMES_BACKUP = process.env.TRIVABBLE_GAMES_BACKUP || "games.backup.json";
const DEFAULT_BOARD_LANG = process.env.TRIVABBLE_DEFAULT_BOARD_LANG || "fr";
const DEFAULT_BOARD_LABEL = process.env.TRIVABBLE_DEFAULT_BOARD_LABEL || "15x15-7";
const DEFAULT_BAG_FACTOR = process.env.TRIVABBLE_DEFAULT_BAG_FACTOR || 1;
const VERSION = 202005070100;
@ -205,26 +208,47 @@ function keepAlive(responseAndType) {
}, KEEP_ALIVE);
}
function newBoard() {
const res = new Array(15 * 15);
function getBoardDimensions(boardLabel) {
return boardLabel
.match(/[0-9]*/gu)
.filter(function (x) {return (x.length !== 0);})
.map(function (x) {return parseInt(x);});
}
for (let i = 0; i < 15 * 15; i++) {
function newBoard(label) {
const [nbRows, nbColumns] = getBoardDimensions(label);
const res = new Array(nbRows * nbColumns);
for (let i = 0; i < nbRows * nbColumns; i++) {
res[i] = "";
}
return res;
}
Game.prototype.init = function (lang) {
this.board = newBoard();
Game.prototype.init = function (lang, label, factor) {
this.label = label || DEFAULT_BOARD_LABEL;
this.factor = factor || DEFAULT_BAG_FACTOR;
this.board = newBoard(this.label);
this.lang = lang || DEFAULT_BOARD_LANG;
this.bag = boardTilesPerLang[this.lang].bag.slice();
const bag = boardTilesPerLang[this.lang].bag.slice();
this.letterValues = boardTilesPerLang[this.lang].letterValues;
this.racks = {};
this.scores = {};
this.lastUpdated = new Date();
this.currentPlayer = "";
factor = this.factor;
this.bag = [];
while (factor > 1) {
this.bag = this.bag.concat(bag.slice());
factor--;
}
if (Math.round(bag.length * factor) > 0) {
shuffleInPlace(bag);
this.bag = this.bag.concat(bag.slice(0, Math.round(bag.length * factor)));
}
shuffleInPlace(this.bag);
};
@ -232,6 +256,8 @@ Game.prototype.toJSON = function () {
return {
board: this.board,
lang: this.lang,
label: this.label,
factor: this.factor,
bag: this.bag,
letterValues: this.letterValues,
racks: this.racks,
@ -243,7 +269,9 @@ Game.prototype.toJSON = function () {
Game.fromJSON = function (obj) {
const game = new Game();
game.board = obj.board || newBoard();
game.label = obj.label || DEFAULT_BOARD_LABEL;
game.factor = obj.factor || DEFAULT_BAG_FACTOR;
game.board = obj.board || newBoard(game.label);
game.lang = obj.lang || DEFAULT_BOARD_LANG;
game.bag = boardTilesPerLang[game.lang].bag.slice();
game.letterValues = boardTilesPerLang[game.lang].letterValues;
@ -401,11 +429,13 @@ Game.prototype.bagPushLetter = function (letter, player) {
};
Game.prototype.reset = function (player) {
this.init(this.lang);
this.init(this.lang, this.label, this.factor);
this.pendingEvents.push({
player: player,
action: "reset",
board: this.board,
label: this.label,
factor: this.factor,
remainingLetters: this.bag.length,
rack: []
});
@ -445,9 +475,12 @@ function countTiles(rack) {
return count;
}
function joinGame(gameNumber) {
function joinGame(gameNumber, message) {
if (!gameNumber) {
gameNumber = newGameId();
if (message) {
message.gameNumber = gameNumber;
}
}
const game = games[gameNumber] || (games[gameNumber] = new Game());
@ -467,6 +500,7 @@ function handleCommand(cmdNumber, message, response) {
game.lastUpdated = new Date();
const playerName = message.playerName;
const [nbRows, nbColumns, rackLength] = getBoardDimensions(game.label);
let rack = null;
const cmd = message.cmds[cmdNumber];
@ -479,6 +513,8 @@ function handleCommand(cmdNumber, message, response) {
gameNumber: gameNumber,
playerName: playerName,
boardLang: game.lang,
boardLabel: game.label,
bagFactor: game.factor,
availableBoardLangs: availableBoardLangs,
currentPlayer: game.currentPlayer,
rack: game.getPlayerRack(playerName),
@ -492,7 +528,7 @@ function handleCommand(cmdNumber, message, response) {
case "hello": {
game.playerJoined(playerName);
reply(message, response, cmdNumber, {error: 0, boardLang: game.lang, version: VERSION});
reply(message, response, cmdNumber, {error: 0, boardLang: game.lang, boardLabel: game.label, bagFactor: game.factor, version: VERSION});
break;
}
@ -520,7 +556,7 @@ function handleCommand(cmdNumber, message, response) {
case "rack":
rack = game.getPlayerRack(playerName);
if (cmd.indexFrom > 6 || cmd.indexFrom < 0) {
if (cmd.indexFrom > rackLength - 1 || cmd.indexFrom < 0) {
reply(message, response, cmdNumber, {error: 1, reason: "Wrong indexFrom"});
return false;
}
@ -538,7 +574,7 @@ function handleCommand(cmdNumber, message, response) {
break;
case "board":
if (cmd.indexFrom < 0 || cmd.indexFrom >= 15 * 15) {
if (cmd.indexFrom < 0 || cmd.indexFrom >= nbRows * nbColumns) {
reply(message, response, cmdNumber, {error: 1, reason: "Wrong indexFrom"});
return false;
}
@ -565,7 +601,7 @@ function handleCommand(cmdNumber, message, response) {
switch (cmd.to) {
case "rack":
if (cmd.indexTo < 0 || cmd.indexTo > 6) {
if (cmd.indexTo < 0 || cmd.indexTo > rackLength - 1) {
reply(message, response, cmdNumber, {error: 1, reason: "Wrong indexTo"});
return false;
}
@ -583,7 +619,7 @@ function handleCommand(cmdNumber, message, response) {
break;
case "board":
if (cmd.indexTo < 0 || cmd.indexTo >= 15 * 15) {
if (cmd.indexTo < 0 || cmd.indexTo >= nbRows * nbColumns) {
reply(message, response, cmdNumber, {error: 1, reason: "Wrong indexTo"});
return false;
}
@ -626,7 +662,7 @@ function handleCommand(cmdNumber, message, response) {
}
case "setRack": {
if (cmd.rack.length > 7) {
if (cmd.rack.length > rackLength) {
reply(message, response, cmdNumber, {
error: 1,
rack: rack,
@ -643,7 +679,7 @@ function handleCommand(cmdNumber, message, response) {
const newRackSorted = cmd.rack.filter((l) => l);
newRackSorted.sort();
for (let i = 0; i < 7; i++) {
for (let i = 0; i < rackLength; i++) {
if ((oldRackSorted[i] !== newRackSorted[i]) && (oldRackSorted[i] || newRackSorted[i])) {
reply(message, response, cmdNumber, {
error: 1,
@ -654,7 +690,7 @@ function handleCommand(cmdNumber, message, response) {
}
}
for (let i = 0; i < 7; i++) {
for (let i = 0; i < rackLength; i++) {
rack[i] = cmd.rack[i];
}
@ -671,21 +707,27 @@ function handleCommand(cmdNumber, message, response) {
case "changeBoard": {
game.lang = cmd.lang || DEFAULT_BOARD_LANG;
game.label = cmd.label || DEFAULT_BOARD_LABEL;
game.factor = cmd.factor || DEFAULT_BAG_FACTOR;
game.reset();
reply(message, response, cmdNumber, {
error: 0,
boardLang: game.lang,
boardLabel: game.label,
bagFactor: game.factor,
letterValues: game.letterValues
});
game.pendingEvents.push({
msg: {
sender: playerName,
content: "I changed the language of the board to " + game.lang,
content: "I changed the board to " + game.label + " in language " + game.lang,
specialMsg: {
type: "changeBoardLang",
newBoardLang: game.lang
type: "changeBoardDef",
newBoardLang: game.lang,
newBoardLabel: game.label,
newBagFactor: game.factor
}
}
});
@ -718,7 +760,7 @@ function handleCommand(cmdNumber, message, response) {
function handleCommands(message, responseAndType) {
if (!message.cmds || !message.cmds.length) {
const {gameNumber, game} = joinGame(message.gameNumber);
const {gameNumber, game} = joinGame(message.gameNumber, message);
writeMessage(responseAndType,
JSON.stringify({
@ -726,6 +768,8 @@ function handleCommands(message, responseAndType) {
currentPlayer: game.currentPlayer,
gameNumber: gameNumber,
boardLang: game.lang,
boardLabel: game.label,
bagFactor: game.factor,
availableBoardLangs: availableBoardLangs,
letterValues: game.letterValues,
rack: game.getPlayerRack(message.playerName),
@ -980,7 +1024,8 @@ function handleRequest(request, response) {
".ogg": "audio/ogg",
".js": "application/javascript; charset=utf-8",
".css": "text/css; charset=utf-8",
".svg": "image/svg+xml"
".svg": "image/svg+xml",
".dict": "text/plain"
};
for (const i in mimes) {
@ -997,6 +1042,24 @@ function handleRequest(request, response) {
}
response.setHeader("Content-Type", mime);
response.setHeader(
"Content-Security-Policy",
"default-src 'none'; " +
"script-src 'self'; " +
"style-src 'self'; " +
"img-src 'self'; " +
(disableCSP ? "connect-src *; " : "connect-src 'self' " + (
// uzbl (like Safari 9 / iPad 2) does not like insecure websockets on the
// same port with connect-src 'self'
// See https://github.com/w3c/webappsec-csp/issues/7
"ws://" + host + ":" + port + " " +
"ws://127.0.0.1:" + port + " " +
"ws://localhost:" + port + "; "
)) +
"media-src 'self'"
);
response.end(contents);
});
} else {
@ -1172,8 +1235,8 @@ fs.readFile(GAMES_BACKUP, function (err, data) {
console.error("An error happened in the HTTP server", error);
});
server.listen(port, host, function() {
console.log("Server listening on: http://localhost:%s", port);
server.listen(port, host, function () {
console.log("Server listening on: http://%s:%s", host, port);
});
});