├── .gitignore ├── t ├── data │ ├── empty.po │ ├── plural.mo │ ├── simple.mo │ ├── context.mo │ ├── overload.mo │ ├── de_DE-2.8.mo │ ├── bad_nplurals.mo │ ├── windows-line-endings.po │ ├── originals.android.xml │ ├── translation.android.xml │ ├── bad_nplurals.po │ ├── mo.pot │ ├── simple.po │ ├── originals.utf16be.strings │ ├── originals.utf16le.strings │ ├── translation.strings │ └── originals.resx.xml ├── .coveralls.yml ├── bin │ └── request.php ├── tests │ ├── test_locale.php │ ├── test_requests.php │ ├── test_install.php │ ├── test_deprecated.php │ ├── tests_testlib │ │ └── test_default_factories.php │ ├── test_strings.php │ ├── test_noop_translations.php │ ├── test_translation_entry.php │ ├── test_links.php │ ├── tests_routes │ │ ├── test_route_api.php │ │ └── test_route_translation.php │ ├── test_misc.php │ ├── test_validation.php │ ├── test_template.php │ ├── test_meta.php │ ├── tests_things │ │ ├── test_thing_glossary.php │ │ └── test_thing_glossary_entry.php │ ├── test_thing.php │ ├── test_user.php │ ├── test_format_android.php │ ├── test_warnings.php │ ├── test_format_resx.php │ └── test_format_strings.php ├── all.php ├── lib │ ├── bootstrap.php │ ├── testcase-request.php │ └── testcase-route.php ├── phpunit.xml.dist └── unittests-config-sample.php ├── gp-templates ├── locales.api.php ├── redirect.php ├── projects.api.php ├── translations.api.php ├── locale.api.php ├── 404.api.php ├── 404.php ├── project.api.php ├── footer.php ├── project-new.php ├── project-edit.php ├── translation-set-new.php ├── profile-public.api.php ├── projects.php ├── translation-set-edit.php ├── login.php ├── project-import.php ├── glossary-new.php ├── glossary-import.php ├── translation-set-form.php ├── project-mass-create-sets.php ├── header.php ├── glossary-edit.php ├── profile.php ├── project-form.php ├── locales.php ├── project-branch.php ├── profile-public.php ├── install.php ├── project-permissions.php └── glossary-entry-row.php ├── img ├── asc.gif ├── desc.gif └── glotpress-logo.png ├── composer.json ├── index.php ├── pomo ├── sample │ ├── languages │ │ ├── bg.mo │ │ ├── bg-side.mo │ │ ├── bg-side.po │ │ ├── app-side.pot │ │ ├── app.pot │ │ └── bg.po │ └── app.php └── entry.php ├── gp-includes ├── routes │ ├── _main.php │ ├── index.php │ ├── original.php │ ├── login.php │ ├── profile.php │ └── translation-set.php ├── backpress │ ├── loader.wp-object-cache.php │ ├── pomo │ │ ├── sample │ │ │ ├── languages │ │ │ │ ├── bg.mo │ │ │ │ ├── bg-side.mo │ │ │ │ ├── bg-side.po │ │ │ │ ├── app-side.pot │ │ │ │ ├── app.pot │ │ │ │ └── bg.po │ │ │ └── app.php │ │ └── entry.php │ ├── loader.wp-object-cache-memcached.php │ ├── functions.bp-options.php │ ├── class.bp-roles.php │ ├── class.wp-http-ixr-client.php │ ├── interface.bp-options.php │ └── functions.wp-scripts.php ├── default-filters.php ├── things │ ├── permission.php │ ├── glossary-entry.php │ ├── validator-permission.php │ └── glossary.php ├── gp.php ├── class.bp-options.php ├── format.php ├── deprecated.php ├── assets-loader.php ├── system.php ├── cli.php ├── formats │ └── format_pomo.php ├── advanced-permissions.php ├── install-upgrade.php ├── plugin.php ├── l10n.php └── template-links.php ├── scripts ├── regenerate-paths.php ├── wporg2slug.php ├── wipe-permissions.php ├── upgrade-set-permissions.php ├── remove-multiple-currents.php ├── add-admin.php ├── branch-project.php ├── recheck-warnings.php ├── import.php ├── export.php └── import-originals.php ├── README ├── .travis.yml ├── .scrutinizer.yml ├── gp-load.php ├── js ├── mass-create-sets-page.js ├── common.js └── translations-page.js ├── css └── install.css ├── plugins └── google-translate │ └── google-translate.js ├── gp-config-sample.php ├── install.php └── HACKING /.gitignore: -------------------------------------------------------------------------------- 1 | .svn -------------------------------------------------------------------------------- /t/data/empty.po: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gp-templates/locales.api.php: -------------------------------------------------------------------------------- 1 | false, 'error' => __('Not Found') ) ); 4 | -------------------------------------------------------------------------------- /pomo/sample/languages/bg.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GlotPress/GlotPress-standalone/HEAD/pomo/sample/languages/bg.mo -------------------------------------------------------------------------------- /pomo/sample/languages/bg-side.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GlotPress/GlotPress-standalone/HEAD/pomo/sample/languages/bg-side.mo -------------------------------------------------------------------------------- /gp-templates/404.php: -------------------------------------------------------------------------------- 1 | redirect( gp_url_project( '' ) ); 5 | } 6 | } -------------------------------------------------------------------------------- /gp-templates/project.api.php: -------------------------------------------------------------------------------- 1 | $translation_sets, 'sub_projects' => $sub_projects ) ); -------------------------------------------------------------------------------- /gp-includes/backpress/pomo/sample/languages/bg-side.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GlotPress/GlotPress-standalone/HEAD/gp-includes/backpress/pomo/sample/languages/bg-side.mo -------------------------------------------------------------------------------- /gp-includes/backpress/loader.wp-object-cache-memcached.php: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /scripts/regenerate-paths.php: -------------------------------------------------------------------------------- 1 | regenerate_paths(); 8 | } 9 | } 10 | $gp_script_regenerate = new GP_Script_Regenerate; 11 | $gp_script_regenerate->run(); -------------------------------------------------------------------------------- /t/bin/request.php: -------------------------------------------------------------------------------- 1 | factory->locale->create(); 8 | $locale->text_direction = 'rtl'; 9 | 10 | $this->assertTrue( isset( $locale->rtl ) ); 11 | $this->assertTrue( $locale->rtl ); 12 | } 13 | 14 | 15 | } -------------------------------------------------------------------------------- /t/tests/test_requests.php: -------------------------------------------------------------------------------- 1 | get( '/' ); 6 | $this->assertRedirect(); 7 | } 8 | 9 | function test_projects() { 10 | $this->get( '/projects' ); 11 | $this->assertResponseContains( 'Projects' ); 12 | $this->assertResponseNotContains( 'baba' ); 13 | } 14 | } -------------------------------------------------------------------------------- /t/tests/test_install.php: -------------------------------------------------------------------------------- 1 | assertEquals( 'http://example.org/', guess_uri() ); 10 | 11 | $_SERVER['SCRIPT_NAME'] = '/glotpress/install.php'; 12 | $this->assertEquals( 'http://example.org/glotpress/', guess_uri() ); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /gp-includes/things/permission.php: -------------------------------------------------------------------------------- 1 | field_names as $field_name ) { 12 | if ( isset( $args[$field_name] ) ) { 13 | $args[$field_name] = $this->force_false_to_null( $args[$field_name] ); 14 | } 15 | } 16 | return $args; 17 | } 18 | } 19 | GP::$permission = new GP_Permission(); -------------------------------------------------------------------------------- /gp-templates/project-new.php: -------------------------------------------------------------------------------- 1 | 8 |

9 |
10 | 11 |

12 | 13 | 14 |

15 |
16 | 2 | 3 | Normal String 4 | I\'m with a quote 5 | new\nlines 6 | double "quotes" 7 | питка 8 | you < me 9 | me > you 10 | me & you are not &amp; 11 | baba 12 | 13 | -------------------------------------------------------------------------------- /t/data/translation.android.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Just A Normal String 4 | I\'m with a quote 5 | I\nhave\nnew\nlines 6 | I have double "quotes" 7 | баба ми омеси питка 8 | ти < аз 9 | аз > ти 10 | аз & ти не сме &amp; 11 | баба 12 | 13 | -------------------------------------------------------------------------------- /t/tests/test_deprecated.php: -------------------------------------------------------------------------------- 1 | assertEquals( "odd", $gen() ); 10 | $this->assertEquals( "odd", $concurrent() ); 11 | $this->assertEquals( "even", $gen() ); 12 | $this->assertEquals( "odd", $gen() ); 13 | $this->assertEquals( "even", $concurrent() ); 14 | $this->assertEquals( "odd", $concurrent() ); 15 | $this->assertEquals( "even", $gen() ); 16 | $this->assertEquals( "even", $concurrent() ); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /t/data/bad_nplurals.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: bbPress 1.0.4 alpha\n" 4 | "POT-Creation-Date: \n" 5 | "PO-Revision-Date: 2008-12-26 17:07+0100\n" 6 | "Last-Translator: Fernando Tellado \n" 7 | "Language-Team: ayudawordpress.com \n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=utf-8\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | "X-Poedit-Language: spanish\n" 12 | "X-Poedit-Country: spain\n" 13 | "Plural-Forms: nplurals=2; plural=n !=1;\\n\n" 14 | 15 | msgid "%d forum" 16 | msgid_plural "%d forums" 17 | msgstr[0] "%d foro" 18 | msgstr[1] "%d foros" 19 | -------------------------------------------------------------------------------- /t/all.php: -------------------------------------------------------------------------------- 1 | addTestSuite( $class ); 19 | } 20 | } 21 | 22 | return $suite; 23 | } 24 | } 25 | 26 | chdir( $old_cwd ); -------------------------------------------------------------------------------- /gp-templates/project-edit.php: -------------------------------------------------------------------------------- 1 | name ) ); 3 | gp_breadcrumb_project( $project ); 4 | gp_tmpl_header(); 5 | ?> 6 |

name ) ) ); ?>

7 |
8 | 9 |

10 | 11 | 12 |

13 |
14 | 6 |

7 |
8 | 9 |

10 | 11 | 12 |

13 |
14 | /install.php -- this will upgrade the database structure 16 | 17 | QUESTIONS 18 | 19 | * Mailing list: http://lists.automattic.com/mailman/listinfo/glotpress 20 | * IRC channel: #glotpress at FreeNode -------------------------------------------------------------------------------- /scripts/wporg2slug.php: -------------------------------------------------------------------------------- 1 | "; 7 | 8 | function run() { 9 | if ( !isset( $this->args[0] ) ) { 10 | $this->usage(); 11 | } 12 | $wporg_slug = $this->args[0]; 13 | $slug = null; 14 | foreach( GP_Locales::locales() as $locale ) { 15 | if ( $locale->wp_locale == $wporg_slug ) { 16 | $slug = $locale->slug; 17 | break; 18 | } 19 | } 20 | if ( !$slug ) 21 | $this->to_stderr("No slug match for $wporg_slug."); 22 | else 23 | echo $slug; 24 | } 25 | } 26 | 27 | $gp_script_wporg2slug = new GP_Script_WPorg2Slug; 28 | $gp_script_wporg2slug->run(); 29 | -------------------------------------------------------------------------------- /t/lib/bootstrap.php: -------------------------------------------------------------------------------- 1 | array( 4 | 'user_display_name' => $user->display_name, 5 | 'user_registered' => $user->user_registered, 6 | ) 7 | ); 8 | 9 | foreach ( $recent_projects as $project ) { 10 | $project->set_name = html_entity_decode( $project->set_name ); 11 | unset($project->project_id); 12 | unset($project->set_id); 13 | } 14 | 15 | $arr = array_merge( $meta, 16 | compact( 'locales', 'recent_projects' ) 17 | ); 18 | 19 | switch ( gp_get('filter') ) { 20 | case 'meta': 21 | echo gp_json_encode( $meta ); 22 | break; 23 | case 'recent_projects': 24 | echo gp_json_encode( compact('recent_projects') ); 25 | break; 26 | default: 27 | echo gp_json_encode( $arr ); 28 | break; 29 | } 30 | -------------------------------------------------------------------------------- /gp-templates/projects.php: -------------------------------------------------------------------------------- 1 | 5 | 6 |

7 | 8 | 13 | 14 |

15 | current()->can( 'write', 'project' ) ): ?> 16 | •  17 | 18 | 19 | 20 |

21 | 22 | , 2008. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PACKAGE VERSION\n" 9 | "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n" 10 | "POT-Creation-Date: 2008-06-06 23:10+0300\n" 11 | "PO-Revision-Date: 2008-06-06 22:54+0300\n" 12 | "Last-Translator: Nikolay Bachiyski \n" 13 | "Language-Team: Bulgarian\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | msgid "A string with low priority!" 19 | msgstr "Смотан низ!" 20 | -------------------------------------------------------------------------------- /gp-templates/translation-set-edit.php: -------------------------------------------------------------------------------- 1 | name, $project->name ) ); 3 | gp_breadcrumb( array( 4 | gp_link_project_get( $project, $project->name ), 5 | gp_link_get( $url, $locale->english_name . 'default' != $set->slug? ' '.$set->name : '' ), 6 | ) ); 7 | gp_tmpl_header(); 8 | ?> 9 |

10 |
11 | 12 |

13 | 14 | or Cancel 15 |

16 |
17 | , 2008. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PACKAGE VERSION\n" 9 | "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n" 10 | "POT-Creation-Date: 2008-06-06 23:10+0300\n" 11 | "PO-Revision-Date: 2008-06-06 22:54+0300\n" 12 | "Last-Translator: Nikolay Bachiyski \n" 13 | "Language-Team: Bulgarian\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | msgid "A string with low priority!" 19 | msgstr "Смотан низ!" 20 | -------------------------------------------------------------------------------- /gp-includes/gp.php: -------------------------------------------------------------------------------- 1 | get( $original_id ); 7 | 8 | if ( ! $original ) { 9 | return $this->die_with_404(); 10 | } 11 | 12 | $project = GP::$project->get( $original->project_id ); 13 | 14 | if ( ! $project ) { 15 | return $this->die_with_404(); 16 | } 17 | 18 | $this->can_or_forbidden( 'write', 'project', $project->id ); 19 | $original->priority = gp_post( 'priority' ); 20 | 21 | if ( ! $original->validate() ) { 22 | return $this->die_with_error( 'Invalid priority value!' ); 23 | } 24 | 25 | if ( ! $original->save() ) { 26 | return $this->die_with_error( 'Error in saving original!' ); 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /pomo/sample/languages/app-side.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n" 11 | "POT-Creation-Date: 2008-06-06 23:10+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=CHARSET\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 19 | 20 | msgid "A string with low priority!" 21 | msgstr "" 22 | -------------------------------------------------------------------------------- /t/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | tests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ../gp-includes/backpress 15 | ../gp-templates 16 | ../plugins 17 | ./ 18 | 19 | ../plugins/google-translate 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /t/data/mo.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR WordPress 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n" 11 | "POT-Creation-Date: 2009-06-28 11:07+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=CHARSET\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | #: wp-admin/includes/continents-cities.php:7 20 | msgid "Africa" 21 | msgstr "" 22 | 23 | #: wp-admin/includes/continents-cities.php:8 24 | msgid "Abidjan" 25 | msgstr "" 26 | -------------------------------------------------------------------------------- /gp-includes/backpress/pomo/sample/languages/app-side.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n" 11 | "POT-Creation-Date: 2008-06-06 23:10+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=CHARSET\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 19 | 20 | msgid "A string with low priority!" 21 | msgstr "" 22 | -------------------------------------------------------------------------------- /scripts/wipe-permissions.php: -------------------------------------------------------------------------------- 1 | delete_all() ) { 11 | echo "Permissions were deleted. Now you can use scripts/add-admin.php to add a new administrator.\n"; 12 | } else { 13 | $this->to_stderr( "Error in deleting permissions." ); 14 | exit( 1 ); 15 | } 16 | } else { 17 | echo "Nothing was deleted.\n"; 18 | } 19 | } 20 | } 21 | 22 | $gp_script_wipe_permissions = new GP_Script_Wipe_Permissions; 23 | $gp_script_wipe_permissions->run(); 24 | -------------------------------------------------------------------------------- /scripts/upgrade-set-permissions.php: -------------------------------------------------------------------------------- 1 | find_many( array( 'object_type' => 'translation-set', 'action' => 'approve' ) ); 8 | foreach( $permissions as $permission ) { 9 | $set = GP::$translation_set->get( $permission->object_id ); 10 | $project = GP::$project->get( $set->project_id ); 11 | GP::$permission->create( array( 12 | 'user_id' => $permission->user_id, 13 | 'action' => 'approve', 14 | 'object_type' => 'project|locale|set-slug', 15 | 'object_id' => $project->id.'|'.$set->locale.'|'.$set->slug, 16 | ) ); 17 | } 18 | } 19 | } 20 | $gp_script_upgrade_permissions = new GP_Script_Upgrade_Permissions; 21 | $gp_script_upgrade_permissions->run(); -------------------------------------------------------------------------------- /scripts/remove-multiple-currents.php: -------------------------------------------------------------------------------- 1 | all(); 8 | foreach( $sets as $set ) { 9 | echo "Processing set#$set->id...\n"; 10 | $translations = GP::$translation->find( array( 'translation_set_id' => $set->id, 'status' => 'current' ), 'original_id ASC' ); 11 | $prev_original_id = null; 12 | foreach( $translations as $translation ) { 13 | if ( $translation->original_id == $prev_original_id ) { 14 | echo "Duplicate with original_id#$prev_original_id. Translation#$translation->id\n"; 15 | $translation->delete(); 16 | } 17 | $prev_original_id = $translation->original_id; 18 | } 19 | } 20 | } 21 | } 22 | 23 | $gp_script = new GP_Script; 24 | $gp_script->run(); 25 | -------------------------------------------------------------------------------- /scripts/add-admin.php: -------------------------------------------------------------------------------- 1 | "; 7 | 8 | function run() { 9 | if ( empty( $this->args ) ) { 10 | $this->usage(); 11 | } 12 | foreach( $this->args as $user_login ) { 13 | $user_to_make_admin = GP::$user->by_login( $user_login ); 14 | if ( !$user_to_make_admin ) { 15 | $this->to_stderr( "User '$user_login' doesn't exist." ); 16 | exit( 1 ); 17 | } 18 | if ( !GP::$permission->create( array( 'user_id' => $user_to_make_admin->id, 'action' => 'admin' ) ) ) { 19 | $this->to_stderr( "Error in making '$user_login' and admin." ); 20 | exit( 2 ); 21 | } 22 | } 23 | 24 | } 25 | } 26 | 27 | $gp_script_add_admin = new GP_Script_Add_Admin; 28 | $gp_script_add_admin->run(); 29 | -------------------------------------------------------------------------------- /t/tests/tests_testlib/test_default_factories.php: -------------------------------------------------------------------------------- 1 | create(); 7 | $this->assertEquals( 'Project 1', $project->name ); 8 | } 9 | 10 | function test_project_factory_original() { 11 | $original_factory = new GP_UnitTest_Factory_For_Original; 12 | $original = $original_factory->create(); 13 | $this->assertEquals( 'Original 1', $original->singular ); 14 | } 15 | 16 | function test_locale_factory_create() { 17 | $locale_factory = new GP_UnitTest_Factory_For_Locale; 18 | $locale = $locale_factory->create(); 19 | $this->assertEquals( 'aa', $locale->slug ); 20 | $this->assertEquals( 'Locale 1', $locale->english_name ); 21 | $this->assertSame( $locale, GP_Locales::by_slug( $locale->slug ) ); 22 | } 23 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | sudo: false 3 | 4 | php: 5 | - 5.3 6 | - 5.4 7 | - 5.5 8 | - 5.6 9 | - hhvm 10 | - nightly 11 | 12 | matrix: 13 | allow_failures: 14 | - php: hhvm 15 | - php: nighly 16 | 17 | before_script: 18 | - mysql -e "CREATE DATABASE glotpress_test;" -uroot 19 | - curl -s http://getcomposer.org/installer | php 20 | - php composer.phar install --dev --no-interaction 21 | - wget https://scrutinizer-ci.com/ocular.phar 22 | - cd t 23 | - cp unittests-config-sample.php unittests-config.php 24 | - sed -i "s/username/travis/" unittests-config.php 25 | - sed -i "s/password//" unittests-config.php 26 | 27 | script: 28 | - mkdir -p build/logs 29 | - phpunit 30 | 31 | after_script: 32 | - php ../vendor/bin/coveralls --config .coveralls.yml -v 33 | - php ../ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml 34 | -------------------------------------------------------------------------------- /scripts/branch-project.php: -------------------------------------------------------------------------------- 1 | -d "; 9 | 10 | function run() { 11 | if ( ! isset( $this->options['s'] ) || !isset( $this->options['d'] ) ) { 12 | $this->usage(); 13 | } 14 | $source_project = GP::$project->by_path( $this->options['s'] ); 15 | if ( ! $source_project ){ 16 | $this->error( __('Source project not found!') ); 17 | } 18 | 19 | $destination_project = GP::$project->by_path( $this->options['d'] ); 20 | if ( ! $destination_project ){ 21 | $this->error( __('Destination project not found!') ); 22 | } 23 | 24 | $destination_project->duplicate_project_contents_from( $source_project ); 25 | 26 | } 27 | } 28 | 29 | $gp_script_import_originals = new GP_Script_Branch_Project; 30 | $gp_script_import_originals->run(); 31 | -------------------------------------------------------------------------------- /scripts/recheck-warnings.php: -------------------------------------------------------------------------------- 1 | get( $translation_set->project_id ); 8 | $locale = GP_Locales::by_slug( $translation_set->locale ); 9 | foreach( GP::$translation->for_translation( $project, $translation_set, 'no-limit' ) as $entry ) { 10 | $warnings = GP::$translation_warnings->check( $entry->singular, $entry->plural, $entry->translations, $locale ); 11 | if ( $warnings != $entry->warnings ) { 12 | $translation = new GP_Translation( array('id' => $entry->id) ); 13 | echo sprintf( __("Updating warnings for %s"), $entry->id ) . "\n"; 14 | $translation->update( array('warnings' => $warnings) ); 15 | } 16 | } 17 | } 18 | 19 | } 20 | $gp_script_recheck_warnings = new GP_Script_Recheck_Warnings; 21 | $gp_script_recheck_warnings->run(); -------------------------------------------------------------------------------- /t/data/simple.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: WordPress 2.6-bleeding\n" 4 | "Plural-Forms: nplurals=2; plural=n != 1;\n" 5 | 6 | msgid "moon" 7 | msgstr "" 8 | 9 | msgctxt "brum" 10 | msgid "strut" 11 | msgid_plural "struts" 12 | msgstr[0] "ztrut0" 13 | msgstr[1] "ztrut1" 14 | msgstr[2] "ztrut2" 15 | 16 | msgid "" 17 | "The first thing you need to do is tell Blogger to let WordPress access your " 18 | "account. You will be sent back here after providing authorization." 19 | msgstr "baba\n" 20 | "dyado" 21 | "gugu" 22 | 23 | msgctxt "" 24 | "con" 25 | "text" 26 | msgid "" 27 | "sing" 28 | "ular" 29 | msgid_plural "" 30 | "plu" 31 | "ral" 32 | msgstr[0] "" 33 | "trans" 34 | "lation0" 35 | msgstr[1] "" 36 | "trans" 37 | "lation1" 38 | msgstr[2] "" 39 | "translation2" 40 | 41 | 42 | 43 | # baba 44 | #: wp-admin/x.php:111 baba:333 45 | #. translators: buuu 46 | # brubru 47 | #, fuzzy 48 | #: baba 49 | msgid "a" 50 | msgstr "" 51 | 52 | msgid "a\"" 53 | msgstr "" 54 | 55 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | excluded_paths: 3 | - gp-includes/backpress/* 4 | - t/* 5 | tools: 6 | js_hint: true 7 | php_code_sniffer: 8 | config: 9 | sniffs: { generic: { php: { disallow_short_open_tag_sniff: true } } } 10 | php_analyzer: 11 | extensions: 12 | - php 13 | filter: 14 | excluded_paths: 15 | - gp-includes/backpress/* 16 | - t/* 17 | php_cpd: 18 | enabled: true 19 | names: 20 | - '*.php' 21 | min_lines: 5 22 | min_tokens: 70 23 | filter: 24 | excluded_paths: 25 | - gp-includes/backpress/* 26 | - t/* 27 | php_pdepend: 28 | enabled: true 29 | suffixes: 30 | - php 31 | filter: 32 | excluded_paths: 33 | - gp-includes/backpress/* 34 | - t/* 35 | external_code_coverage: 36 | timeout: 300 37 | -------------------------------------------------------------------------------- /pomo/sample/languages/app.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n" 11 | "POT-Creation-Date: 2008-06-06 23:10+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=CHARSET\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 19 | 20 | #: app.php:46 21 | #, php-format 22 | msgid "Welcome %s!" 23 | msgstr "" 24 | 25 | #: app.php:48 26 | #, php-format 27 | msgid "You have one new message." 28 | msgid_plural "You have %s new messages." 29 | msgstr[0] "" 30 | msgstr[1] "" 31 | 32 | #: app.php:50 33 | msgid "Bye\n" 34 | msgstr "" 35 | -------------------------------------------------------------------------------- /pomo/sample/languages/bg.po: -------------------------------------------------------------------------------- 1 | # Bulgarian translations for PACKAGE package. 2 | # Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # Nikolay Bachiyski , 2008. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PACKAGE VERSION\n" 9 | "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n" 10 | "POT-Creation-Date: 2008-06-06 23:10+0300\n" 11 | "PO-Revision-Date: 2008-06-06 22:54+0300\n" 12 | "Last-Translator: Nikolay Bachiyski \n" 13 | "Language-Team: Bulgarian\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: app.php:46 19 | #, php-format 20 | msgid "Welcome %s!" 21 | msgstr "Добре дошъл, %s!" 22 | 23 | #: app.php:48 24 | #, php-format 25 | msgid "You have one new message." 26 | msgid_plural "You have %s new messages." 27 | msgstr[0] "Имате едно ново съобщение." 28 | msgstr[1] "Имате %s нови съобщения." 29 | 30 | #: app.php:50 31 | msgid "Bye\n" 32 | msgstr "Чао\n" 33 | -------------------------------------------------------------------------------- /t/tests/test_strings.php: -------------------------------------------------------------------------------- 1 | assertEquals( 'baba', gp_sanitize_for_url( 'baba') ); 6 | $this->assertEquals( 'baba-and-dyado', gp_sanitize_for_url( 'Baba and Dyado') ); 7 | $this->assertEquals( 'баба-и-дядо', gp_sanitize_for_url( 'Баба и Дядо') ); 8 | $this->assertEquals( 'баба-и-дядо', gp_sanitize_for_url( 'Баба и Дядо') ); 9 | $this->assertEquals( 'mu', gp_sanitize_for_url( '/Mu#/') ); 10 | $this->assertEquals( 'баба-дядо', gp_sanitize_for_url( 'Баба & дядо') ); 11 | $this->assertEquals( 'caca-и-цацабууу', gp_sanitize_for_url( 'Caca и цацаБУУУ') ); 12 | } 13 | 14 | function test_gp_string_similarity() { 15 | $string1 = 'Word'; 16 | $string2 = 'Word!'; 17 | $string3 = 'Word'; 18 | 19 | $similarity = gp_string_similarity( $string1, $string2 ); 20 | $similarity_2 = gp_string_similarity( $string1, $string3 ); 21 | 22 | $this->assertEquals( $similarity, 0.775 ); 23 | $this->assertEquals( $similarity_2, 1 ); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /gp-includes/backpress/pomo/sample/languages/app.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n" 11 | "POT-Creation-Date: 2008-06-06 23:10+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=CHARSET\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 19 | 20 | #: app.php:46 21 | #, php-format 22 | msgid "Welcome %s!" 23 | msgstr "" 24 | 25 | #: app.php:48 26 | #, php-format 27 | msgid "You have one new message." 28 | msgid_plural "You have %s new messages." 29 | msgstr[0] "" 30 | msgstr[1] "" 31 | 32 | #: app.php:50 33 | msgid "Bye\n" 34 | msgstr "" 35 | -------------------------------------------------------------------------------- /gp-includes/backpress/pomo/sample/languages/bg.po: -------------------------------------------------------------------------------- 1 | # Bulgarian translations for PACKAGE package. 2 | # Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # Nikolay Bachiyski , 2008. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PACKAGE VERSION\n" 9 | "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n" 10 | "POT-Creation-Date: 2008-06-06 23:10+0300\n" 11 | "PO-Revision-Date: 2008-06-06 22:54+0300\n" 12 | "Last-Translator: Nikolay Bachiyski \n" 13 | "Language-Team: Bulgarian\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: app.php:46 19 | #, php-format 20 | msgid "Welcome %s!" 21 | msgstr "Добре дошъл, %s!" 22 | 23 | #: app.php:48 24 | #, php-format 25 | msgid "You have one new message." 26 | msgid_plural "You have %s new messages." 27 | msgstr[0] "Имате едно ново съобщение." 28 | msgstr[1] "Имате %s нови съобщения." 29 | 30 | #: app.php:50 31 | msgid "Bye\n" 32 | msgstr "Чао\n" 33 | -------------------------------------------------------------------------------- /gp-templates/login.php: -------------------------------------------------------------------------------- 1 | 8 |

9 | 10 |
11 |
12 |
13 |
14 | 15 |
16 |
17 |
18 |

19 | 20 |
21 | 22 | 25 | name ) ) : 4 | sprintf( __('Import Translations < %s < GlotPress'), esc_html( $project->name ) ) ); 5 | gp_breadcrumb_project( $project ); 6 | gp_tmpl_header(); 7 | ?> 8 | 9 |

10 |
11 |
12 |
13 |
14 | $format ) { 17 | $format_options[$slug] = $format->name; 18 | } 19 | $format_dropdown = gp_select( 'format', $format_options, 'po' ); 20 | ?> 21 |
22 |
23 |
24 | 25 | 26 | path, $locale->slug, $translation_set->slug ), $translation_set->name ), 6 | __('Create Glossary') 7 | ) ); 8 | gp_tmpl_header(); 9 | ?> 10 | 11 |

12 |
13 |

14 |
15 | 16 |

17 |

18 | 19 | 20 | 21 |

22 |
23 | 24 | logged_in() ) { 5 | $this->redirect( gp_url( '/' ) ); 6 | return; 7 | } 8 | $this->tmpl( 'login' ); 9 | } 10 | 11 | function login_post() { 12 | global $wp_users_object, $wp_auth_object; 13 | 14 | $user = GP::$user->by_login( $_POST['user_login'] ); 15 | 16 | if ( !$user || is_wp_error($user) ) { 17 | $this->errors[] = __("Invalid username!"); 18 | $this->redirect( gp_url_login() ); 19 | return; 20 | } 21 | 22 | if ( $user->login( gp_post( 'user_pass' ) ) ) { 23 | if ( gp_post( 'redirect_to' ) && ! strpos( gp_post( 'redirect_to' ), 'install.php' ) ) { 24 | $this->redirect( gp_post( 'redirect_to' ) ); 25 | } else { 26 | $this->notices[] = sprintf( __("Welcome, %s!"), $_POST['user_login'] ); 27 | $this->redirect( gp_url_public_root() ); 28 | } 29 | } else { 30 | $this->errors[] = __("Invalid password!"); 31 | $this->redirect( gp_url_login() ); 32 | } 33 | } 34 | 35 | function logout() { 36 | GP::$user->logout(); 37 | $this->redirect( gp_url( '/' ) ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /gp-templates/glossary-import.php: -------------------------------------------------------------------------------- 1 | path, $locale->slug, $translation_set->slug ), $translation_set->name ), 6 | gp_link_get( gp_url_project_locale( $project->path, $locale->slug, $translation_set->slug ) . '/glossary', __('Glossary') ), 7 | __('import') 8 | ) ); 9 | gp_tmpl_header(); 10 | ?> 11 | 12 |

13 |

14 | Google Translator Toolkit.' ), 'https://support.google.com/translate/toolkit/answer/147854' ); ?>
15 |

16 | 17 |
18 |

19 | 20 | 21 |

22 |

23 |
24 | 25 | short_options .= 'f:'; 12 | $this->usage = '-f ' . $this->usage . ' [--disable-propagating]'; 13 | parent::__construct(); 14 | } 15 | 16 | function action_on_translation_set( $translation_set ) { 17 | $po = new PO(); 18 | $po->import_from_file( $this->options['f'] ); 19 | 20 | $disable_propagating = isset( $this->options['disable-propagating'] ); 21 | if ( $disable_propagating ) { 22 | add_filter( 'enable_propagate_translations_across_projects', '__return_false' ); 23 | } 24 | 25 | $added = $translation_set->import( $po ); 26 | 27 | if ( $disable_propagating ) { 28 | remove_filter( 'enable_propagate_translations_across_projects', '__return_false' ); 29 | } 30 | 31 | printf( _n( "%s translation were added\n", "%s translations were added\n", $added ), $added ); 32 | } 33 | 34 | } 35 | $gp_script_import = new GP_Script_Import; 36 | $gp_script_import->run(); 37 | -------------------------------------------------------------------------------- /gp-templates/translation-set-form.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | locale ); ?> 5 | 6 |
7 | 8 |
9 |
10 | 11 | 12 |
13 |
14 | 15 |
16 |
project_id ); ?>
17 |
18 | 19 | 27 | -------------------------------------------------------------------------------- /gp-templates/project-mass-create-sets.php: -------------------------------------------------------------------------------- 1 | name ) ); 3 | gp_breadcrumb_project( $project ); 4 | wp_enqueue_script( 'mass-create-sets-page' ); 5 | wp_localize_script( 'mass-create-sets-page', '$gp_mass_create_sets_options', array( 6 | 'url' => gp_url_join( gp_url_current(), 'preview'), 7 | 'loading' => __('Loading translation sets to create…'), 8 | )); 9 | gp_tmpl_header(); 10 | ?> 11 |

12 |

15 |
16 |
17 |
18 |
19 |
20 |
21 |

22 |
23 | you" = "me > you"; 18 | 19 | /* No comment provided by engineer. */ 20 | "me & you are not &amp;" = "me & you are not &amp;"; 21 | 22 | /* Me, myself & Irene */ 23 | "baba" = "baba"; -------------------------------------------------------------------------------- /t/data/originals.utf16le.strings: -------------------------------------------------------------------------------- 1 | /* No comment provided by engineer. */ 2 | "Normal String" = "Normal String"; 3 | 4 | /* No comment provided by engineer. */ 5 | "I\'m with a quote" = "I'm with a quote"; 6 | 7 | /* No comment provided by engineer. */ 8 | "double \"quotes\"" = "double \"quotes\""; 9 | 10 | /* No comment provided by engineer. */ 11 | "?8B:0" = "?8B:0"; 12 | 13 | /* No comment provided by engineer. */ 14 | "you < me" = "you < me"; 15 | 16 | /* No comment provided by engineer. */ 17 | "me > you" = "me > you"; 18 | 19 | /* No comment provided by engineer. */ 20 | "me & you are not &amp;" = "me & you are not &amp;"; 21 | 22 | /* Me, myself & Irene */ 23 | "baba" = "baba"; -------------------------------------------------------------------------------- /gp-includes/class.bp-options.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <?php echo gp_title(); ?> 6 | 7 | 8 | 9 | 10 | > 11 | 12 | 13 |
14 |

15 | 16 | 17 | 18 |

19 | 20 | 23 | 24 | 27 |
28 | 29 |
30 | 31 | 32 |
33 | 34 | 35 |
36 | 37 |
38 | 39 | 40 | 41 |
42 | 43 |
44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /t/data/translation.strings: -------------------------------------------------------------------------------- 1 | /* No comment provided by engineer. */ 2 | "I'm with a quote" = "I'm with a quote"; 3 | 4 | /* No comment provided by engineer. */ 5 | "Normal String" = "Just A Normal String"; 6 | 7 | /* Me, myself & Irene */ 8 | "baba" = "1010"; 9 | 10 | /* No comment provided by engineer. */ 11 | "double \"quotes\"" = "I have double \"quotes\""; 12 | 13 | /* No comment provided by engineer. */ 14 | "me & you are not &amp;" = "07 & B8 =5 A<5 &amp;"; 15 | 16 | /* No comment provided by engineer. */ 17 | "me > you" = "07 > B8"; 18 | 19 | /* No comment provided by engineer. */ 20 | "you < me" = "B8 < 07"; 21 | 22 | /* No comment provided by engineer. */ 23 | "?8B:0" = "1010 <8 ><5A8 ?8B:0"; 24 | 25 | -------------------------------------------------------------------------------- /gp-includes/routes/profile.php: -------------------------------------------------------------------------------- 1 | logged_in() ) { 6 | $this->redirect( gp_url( '/login?redirect_to=' ).urlencode( gp_url( '/profile') ) ); 7 | return; 8 | } 9 | 10 | $this->tmpl( 'profile' ); 11 | } 12 | 13 | function profile_post() { 14 | if ( isset( $_POST['submit'] ) ) { 15 | $per_page = (int) $_POST['per_page']; 16 | GP::$user->current()->set_meta( 'per_page', $per_page ); 17 | 18 | $default_sort = array( 19 | 'by' => 'priority', 20 | 'how' => 'desc' 21 | ); 22 | $user_sort = wp_parse_args( $_POST['default_sort'], $default_sort ); 23 | 24 | GP::$user->current()->set_meta( 'default_sort', $user_sort ); 25 | } 26 | 27 | $this->redirect( gp_url( '/profile' ) ); 28 | } 29 | 30 | public function profile_view( $user ) { 31 | $user = GP::$user->find_one( array( 'user_nicename' => $user ) ); 32 | 33 | if ( ! $user ) { 34 | return $this->die_with_404(); 35 | } 36 | 37 | $recent_projects = $user->get_recent_translation_sets( 5 ); 38 | $locales = $user->locales_known(); 39 | 40 | //validate to 41 | $permissions = $user->get_permissions(); 42 | 43 | $this->tmpl( 'profile-public', get_defined_vars() ); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /gp-templates/glossary-edit.php: -------------------------------------------------------------------------------- 1 | path, $locale->slug, $translation_set->slug ), $translation_set->name ), 6 | gp_link_get( gp_url_project_locale( $project->path, $locale->slug, $translation_set->slug ) . '/glossary', __('Glossary') ), 7 | __('edit') 8 | ) ); 9 | gp_tmpl_header(); 10 | ?> 11 | 12 |

13 | 14 |
15 |

16 |
17 | 18 |

19 | 20 |

21 | 22 | 23 | 24 | 25 |

26 |
27 | 28 | read_originals_from_file( $file_name ); 21 | 22 | if ( ! $translations ) { 23 | return false; 24 | } 25 | 26 | $originals = GP::$original->by_project_id( $project->id ); 27 | $new_translations = new Translations; 28 | 29 | foreach( $translations->entries as $key => $entry ) { 30 | // we have been using read_originals_from_file to parse the file 31 | // so we need to swap singular and translation 32 | $entry->translations = array( $entry->singular ); 33 | $entry->singular = null; 34 | 35 | foreach( $originals as $original ) { 36 | if ( $original->context == $entry->context ) { 37 | $entry->singular = $original->singular; 38 | break; 39 | } 40 | } 41 | 42 | if ( ! $entry->singular ) { 43 | error_log( sprintf( __("Missing context %s in project #%d"), $entry->context, $project->id ) ); 44 | continue; 45 | } 46 | 47 | $new_translations->add_entry( $entry ); 48 | } 49 | 50 | return $new_translations; 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /t/tests/test_noop_translations.php: -------------------------------------------------------------------------------- 1 | noop = new NOOP_Translations; 7 | $this->entry = new Translation_Entry( array( 'singular' => 'baba' ) ); 8 | $this->plural_entry = new Translation_Entry(array('singular' => 'dyado', 'plural' => 'dyados', 'translations' => array('dyadox', 'dyadoy'))); 9 | } 10 | 11 | function test_get_header() { 12 | $this->assertEquals( false, $this->noop->get_header( 'Content-Type' ) ); 13 | } 14 | 15 | function test_add_entry() { 16 | $this->noop->add_entry( $this->entry ); 17 | $this->assertEquals( array(), $this->noop->entries ); 18 | } 19 | 20 | function test_set_header() { 21 | $this->noop->set_header( 'header', 'value' ); 22 | $this->assertEquals( array(), $this->noop->headers ); 23 | } 24 | 25 | function test_translate_entry() { 26 | $this->noop->add_entry( $this->entry ); 27 | $this->assertEquals( false, $this->noop->translate_entry( $this->entry ) ); 28 | } 29 | 30 | function test_translate() { 31 | $this->noop->add_entry( $this->entry ); 32 | $this->assertEquals( 'baba', $this->noop->translate( 'baba' ) ); 33 | } 34 | 35 | function test_plural() { 36 | $this->noop->add_entry( $this->plural_entry ); 37 | $this->assertEquals( 'dyado', $this->noop->translate_plural( 'dyado', 'dyados', 1 ) ); 38 | $this->assertEquals( 'dyados', $this->noop->translate_plural( 'dyado', 'dyados', 11 ) ); 39 | $this->assertEquals( 'dyados', $this->noop->translate_plural( 'dyado', 'dyados', 0 ) ); 40 | } 41 | } -------------------------------------------------------------------------------- /t/tests/test_translation_entry.php: -------------------------------------------------------------------------------- 1 | empty object 7 | $entry = new Translation_Entry(); 8 | $this->assertNull($entry->singular); 9 | $this->assertNull($entry->plural); 10 | $this->assertFalse($entry->is_plural); 11 | // args -> members 12 | $entry = new Translation_Entry(array( 13 | 'singular' => 'baba', 14 | 'plural' => 'babas', 15 | 'translations' => array('баба', 'баби'), 16 | 'references' => 'should be array here', 17 | 'flags' => 'baba', 18 | )); 19 | $this->assertEquals('baba', $entry->singular); 20 | $this->assertEquals('babas', $entry->plural); 21 | $this->assertTrue($entry->is_plural); 22 | $this->assertEquals(array('баба', 'баби'), $entry->translations); 23 | $this->assertEquals(array(), $entry->references); 24 | $this->assertEquals(array(), $entry->flags); 25 | } 26 | 27 | function test_key() { 28 | $entry_baba = new Translation_Entry(array('singular' => 'baba',)); 29 | $entry_dyado = new Translation_Entry(array('singular' => 'dyado',)); 30 | $entry_baba_ctxt = new Translation_Entry(array('singular' => 'baba', 'context' => 'x')); 31 | $entry_baba_plural = new Translation_Entry(array('singular' => 'baba', 'plural' => 'babas')); 32 | $this->assertEquals($entry_baba->key(), $entry_baba_plural->key()); 33 | $this->assertNotEquals($entry_baba->key(), $entry_baba_ctxt->key()); 34 | $this->assertNotEquals($entry_baba_plural->key(), $entry_baba_ctxt->key()); 35 | $this->assertNotEquals($entry_baba->key(), $entry_dyado->key()); 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /gp-includes/deprecated.php: -------------------------------------------------------------------------------- 1 | assertEquals( 'Baba', gp_link_get( 'http://dir.bg/', 'Baba' ) ); 7 | } 8 | 9 | function test_gp_link_get_attributes() { 10 | $this->assertEquals( 'Baba', 11 | gp_link_get( 'http://dir.bg/', 'Baba', array( 'target' => '_blank', 'class' => 'edit' ) ) ); 12 | } 13 | 14 | function test_gp_link_get_should_put_the_before_attribute_before_the_link() { 15 | $this->assertEquals( 'xBaba', gp_link_get( 'http://dir.bg/', 'Baba', array( 'before' => 'x' ) ) ); 16 | } 17 | 18 | function test_gp_link_get_should_put_the_after_attribute_after_the_link() { 19 | $this->assertEquals( 'Babax', gp_link_get( 'http://dir.bg/', 'Baba', array( 'after' => 'x' ) ) ); 20 | } 21 | 22 | function test_gp_link_get_should_put_the_before_and_after_attributes_before_and_after_the_link() { 23 | $this->assertEquals( 'aBabab', gp_link_get( 'http://dir.bg/', 'Baba', array( 'before' => 'a', 'after' => 'b' ) ) ); 24 | } 25 | 26 | function test_gp_link_get_escape() { 27 | $this->assertEquals( 'Baba & Dyado', gp_link_get( 'http://dir.bg/', 'Baba & Dyado' ) ); 28 | // clean_url() is too restrictive, so it isn't called 29 | //$this->assertEquals( 'Baba', gp_link_get( 'http://dir.bg/?x=5&y=11', 'Baba' ) ); 30 | $this->assertEquals( 'Baba', gp_link_get( 'http://dir.bg/', 'Baba', array( 'a' => '"') ) ); 31 | } 32 | } -------------------------------------------------------------------------------- /gp-templates/profile.php: -------------------------------------------------------------------------------- 1 | current()->get_meta('per_page'); 7 | if ( 0 == $per_page ) 8 | $per_page = 15; 9 | 10 | $default_sort = GP::$user->current()->sort_defaults(); 11 | ?> 12 |

13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 31 | 32 | 33 | 34 | 40 | 41 |
__('Date added (original)'), 24 | 'translation_date_added' => __('Date added (translation)'), 25 | 'original' => __('Original string'), 26 | 'translation' => __('Translation'), 27 | 'priority' => __('Priority'), 28 | 'references' => __('Filename in source'), 29 | 'random' => __('Random'), 30 | ), gp_array_get( $default_sort, 'by', 'priority' ) ); ?>
__('Ascending'), 37 | 'desc' => __('Descending'), 38 | ), gp_array_get( $default_sort, 'how', 'desc' ) ); 39 | ?>
42 |
43 | "> 44 |
45 | 46 | set = $this->factory->translation_set->create_with_project_and_locale(); 9 | $this->route->api = true; 10 | } 11 | 12 | function test_api_projects_list_count() { 13 | $this->route->index(); 14 | $response = $this->api_response(); 15 | 16 | $this->assertEquals( count( GP::$project->all() ), count( $response ) ); 17 | } 18 | 19 | function test_api_projects_list_contains_expected_project() { 20 | $this->route->index(); 21 | $response = $this->api_response(); 22 | $first_project = reset( $response ); 23 | 24 | $this->assertEquals( $this->set->project->id, $first_project->id ); 25 | $this->assertEquals( $this->set->project->name, $first_project->name ); 26 | } 27 | 28 | function test_api_project_has_translation_sets() { 29 | $this->route->single($this->set->project->path); 30 | $response = $this->api_response(); 31 | 32 | $this->assertObjectHasAttribute( 'translation_sets', $response ); 33 | $this->assertFalse( empty( $response->translation_sets ) ); 34 | } 35 | 36 | function test_api_project_translation_set_exposes_keys_with_counts() { 37 | $this->route->single($this->set->project->path); 38 | $response = $this->api_response(); 39 | 40 | $first_set = reset( $response->translation_sets ); 41 | 42 | $this->assertObjectHasAttribute( 'current_count', $first_set ); 43 | $this->assertObjectHasAttribute( 'untranslated_count', $first_set ); 44 | $this->assertObjectHasAttribute( 'waiting_count', $first_set ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /gp-includes/assets-loader.php: -------------------------------------------------------------------------------- 1 | base_url = gp_url_base( 'css' ); 8 | $styles->default_version = gp_get_option( 'version' ); 9 | // TODO: get text direction for current locale 10 | //$styles->text_direction = 'rtl' == get_bloginfo( 'text_direction' ) ? 'rtl' : 'ltr'; 11 | $styles->text_direction = 'ltr'; 12 | 13 | $styles->add( 'base', '/style.css', array(), '20150717' ); 14 | $styles->add( 'install', '/install.css', array('base'), '20140902' ); 15 | } 16 | 17 | add_action( 'wp_default_styles', 'gp_styles_default' ); 18 | 19 | function gp_scripts_default( &$scripts ) { 20 | $scripts->base_url = gp_url_base( 'js' ); 21 | $scripts->default_version = gp_get_option( 'version' ); 22 | 23 | $bump = '20150430'; 24 | 25 | $scripts->add( 'jquery', '/jquery/jquery.js', array(), '1.11' ); 26 | $scripts->add( 'jquery-ui', '/jquery/jquery-ui.js', array('jquery'), '1.10.4' ); 27 | $scripts->add( 'jquery-ui-autocomplete', null, array('jquery-ui'), '1.10.4' ); 28 | $scripts->add( 'jquery-ui-selectable', null, array('jquery-ui'), '1.10.4' ); 29 | $scripts->add( 'jquery-ui-tabs', null, array('jquery-ui'), '1.10.4' ); 30 | $scripts->add( 'tablesorter', '/jquery.tablesorter.min.js', array('jquery'), '1.10.4' ); 31 | 32 | $scripts->add( 'common', '/common.js', array( 'jquery' ), $bump ); 33 | $scripts->add( 'editor', '/editor.js', array( 'common' ), $bump ); 34 | $scripts->add( 'glossary', '/glossary.js', array( 'common' ), $bump ); 35 | $scripts->add( 'translations-page', '/translations-page.js', array( 'common' ), $bump ); 36 | $scripts->add( 'mass-create-sets-page', '/mass-create-sets-page.js', array( 'common' ), $bump ); 37 | } 38 | 39 | add_action( 'wp_default_scripts', 'gp_scripts_default' ); 40 | -------------------------------------------------------------------------------- /scripts/export.php: -------------------------------------------------------------------------------- 1 | array( 'key' => 'term', 'desc' => 'search term' ), 8 | 'q' => array( 'key' => 'status', 'desc' => 'translation string status' ), 9 | ); 10 | 11 | function __construct() { 12 | $this->short_options .= 'o:'; 13 | $this->usage .= ' [-o ]'; 14 | $this->add_filters_to_options_and_usage(); 15 | parent::__construct(); 16 | } 17 | 18 | function action_on_translation_set( $translation_set ) { 19 | 20 | $format = gp_array_get( GP::$formats, isset( $this->options['o'] )? $this->options['o'] : 'po', null ); 21 | if ( !$format ) $this->error( __('No such format.') );; 22 | 23 | $entries = GP::$translation->for_export( $this->project, $translation_set, $this->get_filters_for_translation() ); 24 | echo $format->print_exported_file( $this->project, $this->locale, $translation_set, $entries )."\n"; 25 | } 26 | 27 | function add_filters_to_options_and_usage() { 28 | foreach( $this->filter_options as $option => $details ) { 29 | $this->short_options .= "$option:"; 30 | $this->usage .= " [-$option <{$details['desc']}>]"; 31 | } 32 | } 33 | 34 | function get_filters_for_translation() { 35 | $filters = array(); 36 | foreach( $this->filter_options as $option => $option_details ) { 37 | if ( isset( $this->options[$option] ) ) { 38 | $filters[$option_details['key']] = $this->options[$option]; 39 | } 40 | } 41 | // Default to status=current for critical query efficiency 42 | if ( empty( $filters['status'] ) ) 43 | $filters['status'] = 'current'; 44 | return $filters; 45 | } 46 | } 47 | $gp_script_export = new GP_Script_Export; 48 | $gp_script_export->run(); 49 | -------------------------------------------------------------------------------- /t/data/originals.resx.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | text/microsoft-resx 5 | 6 | 7 | 2.0 8 | 9 | 10 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 11 | 12 | 13 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 14 | 15 | 16 | Eula.txt;System.String, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e;Windows-1252 17 | 18 | 19 | Normal String 20 | 21 | 22 | I'm with a quote 23 | 24 | 25 | 26 | new 27 | lines 28 | 29 | 30 | double "quotes" 31 | 32 | 33 | питка 34 | 35 | 36 | you < me 37 | 38 | 39 | me > you 40 | 41 | 42 | me & you are not &amp; 43 | 44 | 45 | baba 46 | Me, myself & Irene 47 | 48 | 49 | -------------------------------------------------------------------------------- /t/tests/test_misc.php: -------------------------------------------------------------------------------- 1 | assertEquals( array(), gp_array_flatten( array() ) ); 7 | $this->assertEquals( array( 1, 2, 3 ), gp_array_flatten( array( 1, array( 2, 3 ) ) ) ); 8 | $this->assertEquals( array( 1, 2, 3, 4, 5, 6, 7 ), gp_array_flatten( array( 1, array( 2, array( 3, 4 ), 5, ), 6, array( 7 ) ) ) ); 9 | } 10 | 11 | function test_gp_array_zip() { 12 | $this->assertEquals( array(), gp_array_zip() ); 13 | $this->assertEquals( array(), gp_array_zip( array() ) ); 14 | $this->assertEquals( array(), gp_array_zip( array(), array(), array() ) ); 15 | $this->assertEquals( array( array('baba') ), gp_array_zip( array('baba') ) ); 16 | $this->assertEquals( array(), gp_array_zip( array('baba'), array(), array() ) ); 17 | $this->assertEquals( array( array('baba', 'dyado') ), gp_array_zip( array('baba'), array('dyado') ) ); 18 | $this->assertEquals( array( array('baba', 'dyado') ), gp_array_zip( array('baba', 'boom'), array('dyado') ) ); 19 | $this->assertEquals( array( array( array('baba'), 'dyado') ), gp_array_zip( array( array('baba'), 'boom'), array('dyado') ) ); 20 | } 21 | 22 | function test_gp_array_any() { 23 | $this->assertEquals( false, gp_array_any( 'intval', array( 0 ) ) ); 24 | $this->assertEquals( false, gp_array_any( returner(false), array( 1, 2, 3, 4 ) ) ); 25 | $this->assertEquals( false, gp_array_any( returner(true), array() ) ); 26 | $this->assertEquals( true, gp_array_any( returner(true), array( 1, 2, 3, 4 ) ) ); 27 | $this->assertEquals( true, gp_array_any( returner('$x', '$x % 2'), array( 1, 2, 3, 4 ) ) ); 28 | } 29 | 30 | function test_gp_object_has_var_returs_true_if_var_is_null() { 31 | $this->assertTrue( gp_object_has_var( (object)array( 'baba' => null), 'baba' ) ); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /gp-templates/project-form.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 |
7 |
8 | 9 | 10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 | 18 | %file% and %line%. Ex. https://trac.example.org/browser/%file%#L%line%'); ?> 19 |
20 | 21 |
22 |
parent_project_id); ?>
23 | 24 |
active ); ?> />
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /gp-includes/system.php: -------------------------------------------------------------------------------- 1 | $v ) { 22 | if ( !in_array( $k, $noUnset ) && isset( $GLOBALS[$k] ) ) { 23 | $GLOBALS[$k] = NULL; 24 | unset( $GLOBALS[$k] ); 25 | } 26 | } 27 | } 28 | 29 | function gp_urldecode_deep($value) { 30 | $value = is_array( $value ) ? array_map( 'gp_urldecode_deep', $value ) : urldecode( $value ); 31 | return $value; 32 | } 33 | 34 | //TODO: add server-guessing code from bb-load.php in a function here 35 | 36 | function gp_is_installed() { 37 | // Check cache first. If the tables go away and we have true cached, oh well. 38 | if ( wp_cache_get( 'gp_is_installed' ) ) 39 | return true; 40 | 41 | global $gpdb; 42 | $gpdb->flush(); 43 | $gpdb->suppress_errors(); 44 | $gpdb->query("SELECT id FROM $gpdb->translations WHERE 1=0"); 45 | $gpdb->suppress_errors(false); 46 | $installed = ! (bool) $gpdb->last_error; 47 | wp_cache_set( 'gp_is_installed', $installed ); 48 | return $installed; 49 | } 50 | 51 | /** 52 | * Makes all key/value pairs in $vars global variables 53 | */ 54 | function gp_set_globals( $vars ) { 55 | foreach( $vars as $name => $value ) { 56 | $GLOBALS[ $name ] = $value; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /t/tests/test_validation.php: -------------------------------------------------------------------------------- 1 | name_should_not_be('empty'); 10 | $project->rating_should_be('positive_int'); 11 | } 12 | 13 | function normalize_fields( $args ) { 14 | $args = (array)$args; 15 | if ( isset( $args['cat_id'] ) ) { 16 | $args['cat_id'] = $this->force_false_to_null( $args['cat_id'] ); 17 | } 18 | return $args; 19 | } 20 | } 21 | 22 | 23 | class GP_Test_Validation extends GP_UnitTestCase { 24 | function setUp() { 25 | parent::setUp(); 26 | 27 | global $gpdb; 28 | $gpdb->mice = ''; 29 | } 30 | 31 | function test_basic() { 32 | $mickey = new Mouse( array( 'id' => 5, 'name' => 'Mickey', 'rating' => 11, 'cat_id' => 1, ) ); 33 | $this->assertEquals( true, $mickey->validate() ); 34 | $minnie = new Mouse( array( 'id' => 5, 'name' => '', 'rating' => 11, 'cat_id' => 1, ) ); 35 | $this->assertEquals( false, $minnie->validate() ); 36 | } 37 | 38 | function test_is_int() { 39 | $callback = GP_Validators::get( 'int' ); 40 | $f = $callback['positive']; 41 | $this->assertEquals( true, $f('0') ); 42 | $this->assertEquals( true, $f('1') ); 43 | $this->assertEquals( true, $f('-1') ); 44 | $this->assertEquals( true, $f('514') ); 45 | $this->assertEquals( true, $f('-514') ); 46 | $this->assertEquals( false, $f('aaa1aaa') ); 47 | $this->assertEquals( false, $f('2.3') ); 48 | $this->assertEquals( false, $f('aaa1') ); 49 | $this->assertEquals( false, $f('1aaa') ); 50 | } 51 | 52 | function test_between() { 53 | $callback = GP_Validators::get( 'between' ); 54 | $f = $callback['positive']; 55 | $this->assertEquals( true, $f( 0, -1, 2 ) ); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /t/tests/test_template.php: -------------------------------------------------------------------------------- 1 | assertEquals( '', gp_breadcrumb() ); 12 | } 13 | 14 | function test_gp_breadcrumb_should_run_empty_string_through_filter_without_params() { 15 | $filter = $this->getMock('Dummy', array('breadcrumb_filter')); 16 | $filter->expects( $this->once() )->method( 'breadcrumb_filter' )->with( $this->equalTo( array() ) ); 17 | 18 | add_filter( 'gp_breadcrumb_items', array( $filter, 'breadcrumb_filter') ); 19 | gp_breadcrumb(); 20 | remove_filter( 'gp_breadcrumb_items', array( $filter, 'breadcrumb_filter') ); 21 | } 22 | 23 | function test_gp_breadcrumb_should_display_default_list() { 24 | gp_breadcrumb( array( 'baba', 'dyado') ); 25 | $this->assertEquals( '', gp_breadcrumb() ); 26 | } 27 | 28 | function test_gp_breadcrumb_should_join_all_crumbs() { 29 | gp_breadcrumb( array( 'baba', 'dyado') ); 30 | $this->assertEquals( 'babadyado', gp_breadcrumb( null, array( 'before' => '', 'after' => '', 'breadcrumb-template' => '{breadcrumb}' ) ) ); 31 | } 32 | 33 | function test_gp_breadcrumb_should_use_the_before_argument() { 34 | gp_breadcrumb( array( 'baba', 'dyado') ); 35 | $this->assertEquals( '---baba---dyado', gp_breadcrumb( null, array( 'before' => '---', 'after' => '', 'breadcrumb-template' => '{breadcrumb}' ) ) ); 36 | } 37 | 38 | function test_gp_breadcrumb_should_flatten_the_given_array_of_crumbs() { 39 | gp_breadcrumb( array( 'baba', array( 'dyado' ), 'muu' ) ); 40 | $this->assertEquals( 'babadyadomuu', gp_breadcrumb( null, array( 'before' => '', 'after' => '', 'breadcrumb-template' => '{breadcrumb}' ) ) ); 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /t/tests/test_meta.php: -------------------------------------------------------------------------------- 1 | assertEquals( 'bar', gp_get_meta( 'thing', '1', 'foo' ) ); 8 | } 9 | 10 | function test_delete_meta_without_value_should_delete_meta() { 11 | gp_update_meta( '1', 'foo', 'bar', 'thing' ); 12 | gp_delete_meta( '1', 'foo', null, 'thing' ); 13 | $this->assertEquals( null, gp_get_meta( 'thing', '1', 'foo' ) ); 14 | } 15 | 16 | function test_delete_meta_with_value_should_delete_only_meta_with_value() { 17 | gp_update_meta( '1', 'foo', 'bar', 'thing' ); 18 | gp_delete_meta( '1', 'foo', 'bar', 'thing' ); 19 | $this->assertEquals( null, gp_get_meta( 'thing', '1', 'foo' ) ); 20 | 21 | gp_update_meta( '1', 'foo', 'foo', 'thing' ); 22 | gp_delete_meta( '1', 'foo', 'bar', 'thing' ); 23 | $this->assertNotEquals( null, gp_get_meta( 'thing', '1', 'foo' ) ); 24 | } 25 | 26 | /** 27 | * @ticket 480 28 | */ 29 | function test_get_meta_uses_cache() { 30 | global $gpdb; 31 | 32 | gp_update_meta( '1', 'foo', 'bar', 'thing' ); 33 | 34 | $num_queries = $gpdb->num_queries; 35 | 36 | // Cache is not primed, expect 1 query. 37 | gp_get_meta( 'thing', '1', 'foo' ); 38 | $this->assertEquals( $num_queries + 1, $gpdb->num_queries ); 39 | 40 | $num_queries = $gpdb->num_queries; 41 | 42 | // Cache is primed, expect no queries. 43 | gp_get_meta( 'thing', '1', 'foo' ); 44 | $this->assertEquals( $num_queries, $gpdb->num_queries ); 45 | } 46 | 47 | /** 48 | * @ticket 480 49 | */ 50 | function test_get_meta_without_meta_key() { 51 | gp_update_meta( '1', 'key1', 'foo', 'thing' ); 52 | gp_update_meta( '1', 'key2', 'foo', 'thing' ); 53 | 54 | $meta = gp_get_meta( 'thing', '1' ); 55 | $this->assertCount( 2, $meta ); 56 | $this->assertEqualSets( array( 'key1', 'key2' ), array_keys( $meta ) ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pomo/sample/app.php: -------------------------------------------------------------------------------- 1 | translate($text); 10 | } 11 | 12 | function _e($text, $domain = 'default') { 13 | $translations = &get_translations($domain); 14 | echo $translations->translate($text); 15 | } 16 | 17 | function __n($singular, $plural, $count, $domain = 'default') { 18 | $translations = &get_translations($domain); 19 | return $translations->translate_plural($singular, $plural, $count); 20 | } 21 | 22 | function &load_translations($mo_filename) { 23 | if (is_readable($mo_filename)) { 24 | $translations = new MO(); 25 | $translations->import_from_file($mo_filename); 26 | } else { 27 | $translations = new Translations(); 28 | } 29 | return $translations; 30 | } 31 | 32 | // get the locale from somewhere: subomain, config, GET var, etc. 33 | // it can be safely empty 34 | $locale = 'bg'; 35 | $translations = array(); 36 | $empty_translations = & new Translations(); 37 | 38 | function load_textdomain($domain, $mofile) { 39 | global $translations; 40 | $translations[$domain] = &load_translations($mofile); 41 | } 42 | 43 | function &get_translations($domain) { 44 | global $translations, $empty_translations; 45 | return isset($translations[$domain])? $translations[$domain] : $empty_translations; 46 | } 47 | 48 | // load the translations 49 | load_textdomain('default', "languages/$locale.mo"); 50 | load_textdomain('side', "languages/$locale-side.mo"); 51 | 52 | //here comes the real app 53 | $user = 'apok'; 54 | $messages = rand(0, 2); 55 | 56 | printf(__('Welcome %s!')."\n", $user); 57 | 58 | printf(__n('You have one new message.', 'You have %s new messages.', $messages)."\n", $messages); 59 | 60 | echo __("A string with low priority!", 'side')."\n"; 61 | 62 | _e("Bye\n"); 63 | -------------------------------------------------------------------------------- /gp-includes/backpress/pomo/sample/app.php: -------------------------------------------------------------------------------- 1 | translate($text); 10 | } 11 | 12 | function _e($text, $domain = 'default') { 13 | $translations = &get_translations($domain); 14 | echo $translations->translate($text); 15 | } 16 | 17 | function __n($singular, $plural, $count, $domain = 'default') { 18 | $translations = &get_translations($domain); 19 | return $translations->translate_plural($singular, $plural, $count); 20 | } 21 | 22 | function &load_translations($mo_filename) { 23 | if (is_readable($mo_filename)) { 24 | $translations = new MO(); 25 | $translations->import_from_file($mo_filename); 26 | } else { 27 | $translations = new Translations(); 28 | } 29 | return $translations; 30 | } 31 | 32 | // get the locale from somewhere: subomain, config, GET var, etc. 33 | // it can be safely empty 34 | $locale = 'bg'; 35 | $translations = array(); 36 | $empty_translations = & new Translations(); 37 | 38 | function load_textdomain($domain, $mofile) { 39 | global $translations; 40 | $translations[$domain] = &load_translations($mofile); 41 | } 42 | 43 | function &get_translations($domain) { 44 | global $translations, $empty_translations; 45 | return isset($translations[$domain])? $translations[$domain] : $empty_translations; 46 | } 47 | 48 | // load the translations 49 | load_textdomain('default', "languages/$locale.mo"); 50 | load_textdomain('side', "languages/$locale-side.mo"); 51 | 52 | //here comes the real app 53 | $user = 'apok'; 54 | $messages = rand(0, 2); 55 | 56 | printf(__('Welcome %s!')."\n", $user); 57 | 58 | printf(__n('You have one new message.', 'You have %s new messages.', $messages)."\n", $messages); 59 | 60 | echo __("A string with low priority!", 'side')."\n"; 61 | 62 | _e("Bye\n"); 63 | -------------------------------------------------------------------------------- /js/mass-create-sets-page.js: -------------------------------------------------------------------------------- 1 | jQuery(function($) { 2 | $gp.notices.init(); 3 | $('#project_id').change(function() { 4 | var select = $(this); 5 | var project_id = $('option:selected', select).attr('value'); 6 | if ( !project_id ) { 7 | $('#submit').prop('disabled', true); 8 | $('#preview').hide(); 9 | return; 10 | } 11 | $gp.notices.notice($gp_mass_create_sets_options.loading); 12 | select.prop('disabled', true); 13 | $.ajax({type: "POST", url: $gp_mass_create_sets_options.url, data: {project_id: project_id}, dataType: 'json', 14 | success: function(data){ 15 | select.prop('disabled', false); 16 | $gp.notices.clear(); 17 | if (data.added.length || data.removed.length) $('#submit').prop('disabled', false); 18 | var preview = $('#preview'); 19 | preview.html('

Preview changes:

'); 20 | var preview_html = ''; 21 | preview_html += '
    '; 22 | function preview_html_for(kind, text) { 23 | var sets = data[kind]; 24 | var html = ''; 25 | html += '
  • '+text.replace('{count}', sets.length)+''; 26 | if (sets.length) { 27 | html += '
      '; 28 | $.each(sets, function() { 29 | html += '
    • '+$gp.esc_html(this.name)+' ('+this.locale+'/'+this.slug+')
    • '; 30 | }); 31 | html += '
    '; 32 | } 33 | html += '
  • '; 34 | return html; 35 | } 36 | preview_html += preview_html_for('added', '{count} set(s) will be added'); 37 | preview_html += preview_html_for('removed', '{count} set(s) will be removed'); 38 | preview_html += '
'; 39 | preview.append(preview_html); 40 | preview.fadeIn(); 41 | }, 42 | error: function(xhr, msg, error) { 43 | select.prop('disabled', false); 44 | msg = xhr.responsehtml? 'Error: '+ xhr.responsehtml : 'Error saving the translation!'; 45 | $gp.notices.error(msg); 46 | } 47 | }); 48 | }); 49 | $('#submit').prop('disabled', true); 50 | $('#preview').hide(); 51 | }); 52 | -------------------------------------------------------------------------------- /gp-includes/things/glossary-entry.php: -------------------------------------------------------------------------------- 1 | setup_pos(); 13 | } 14 | 15 | function setup_pos(){ 16 | if ( ! empty( $this->parts_of_speech ) ) { 17 | return; 18 | } 19 | 20 | $this->parts_of_speech = array( 21 | 'noun' => _x( 'noun', 'part-of-speech' ), 22 | 'verb' => _x( 'verb','part-of-speech' ), 23 | 'adjective' => _x( 'adjective', 'part-of-speech' ), 24 | 'adverb' => _x( 'adverb', 'part-of-speech' ), 25 | 'interjection' => _x( 'interjection', 'part-of-speech' ), 26 | 'conjunction' => _x( 'conjunction', 'part-of-speech' ), 27 | 'preposition' => _x( 'preposition', 'part-of-speech' ), 28 | 'pronoun' => _x( 'pronoun', 'part-of-speech' ), 29 | 'expression' => _x( 'expression', 'part-of-speech' ) 30 | ); 31 | } 32 | 33 | function restrict_fields( $glossary_entry ) { 34 | $glossary_entry->term_should_not_be( 'empty' ); 35 | $glossary_entry->part_of_speech_should_not_be( 'empty' ); 36 | $glossary_entry->glossary_id_should_be( 'positive_int' ); 37 | $glossary_entry->last_edited_by_should_be( 'positive_int' ); 38 | } 39 | 40 | function by_glossary_id( $glossary_id ) { 41 | return $this->many( "SELECT * FROM $this->table WHERE glossary_id= %d ORDER by term ASC", $glossary_id ); 42 | } 43 | 44 | function last_modified( $glossary ) { 45 | global $gpdb; 46 | 47 | return $gpdb->get_var( $gpdb->prepare( "SELECT date_modified FROM {$this->table} WHERE glossary_id = %d ORDER BY date_modified DESC LIMIT 1", $glossary->id, 'current' ) ); 48 | } 49 | } 50 | 51 | GP::$glossary_entry = new GP_Glossary_Entry(); -------------------------------------------------------------------------------- /t/tests/tests_things/test_thing_glossary.php: -------------------------------------------------------------------------------- 1 | create_and_select( array( 'translation_set_id' => '' ) ); 7 | $verdict = $glossary->validate(); 8 | 9 | $this->assertFalse( $verdict ); 10 | } 11 | 12 | function test_by_set_id() { 13 | $glossary_1 = GP::$glossary->create_and_select( array( 'translation_set_id' => '1' ) ); 14 | $glossary_2 = GP::$glossary->create_and_select( array( 'translation_set_id' => '2' ) ); 15 | $new = GP::$glossary->by_set_id( '1' ); 16 | $this->assertEquals( $glossary_1, $new ); 17 | $this->assertNotEquals( $glossary_2, $new ); 18 | } 19 | 20 | function test_by_set_or_parent_project() { 21 | $locale = $this->factory->locale->create( array( 'slug' => 'bg' ) ); 22 | 23 | $root = $this->factory->project->create( array( 'name' => 'root' ) ); 24 | $root_set = $this->factory->translation_set->create( array( 'project_id' => $root->id, 'locale' => $locale->slug ) ); 25 | 26 | $sub = $this->factory->project->create( array( 'name' => 'sub', 'parent_project_id' => $root->id ) ); 27 | $sub_set = $this->factory->translation_set->create( array( 'project_id' => $sub->id, 'locale' => $locale->slug ) ); 28 | 29 | $subsub = $this->factory->project->create( array( 'name' => 'subsub', 'parent_project_id' => $sub->id ) ); 30 | $subsub_set = $this->factory->translation_set->create( array( 'project_id' => $subsub->id, 'locale' => $locale->slug ) ); 31 | 32 | $glossary = GP::$glossary->create_and_select( array( 'translation_set_id' => $root_set->id ) ); 33 | 34 | $sub_glossary = GP::$glossary->by_set_or_parent_project( $sub_set, $sub ); 35 | $this->assertEquals( $glossary, $sub_glossary ); 36 | $this->assertEquals( $glossary->path(), $sub_glossary->path() ); 37 | 38 | $subsub_glossary = GP::$glossary->by_set_or_parent_project( $subsub_set, $subsub ); 39 | $this->assertEquals( $glossary, $subsub_glossary ); 40 | $this->assertEquals( $glossary->path(), $subsub_glossary->path() ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /gp-includes/things/validator-permission.php: -------------------------------------------------------------------------------- 1 | project_id_should_not_be('empty'); 11 | $permission->locale_slug_should_not_be('empty'); 12 | $permission->user_id_should_not_be('empty'); 13 | $permission->action_should_not_be('empty'); 14 | $permission->set_slug_should_not_be('empty'); 15 | } 16 | 17 | function set_fields( $db_object ) { 18 | parent::set_fields( $db_object ); 19 | if ( $this->object_id ) { 20 | list( $this->project_id, $this->locale_slug, $this->set_slug ) = $this->project_id_locale_slug_set_slug( $this->object_id ); 21 | } 22 | $this->object_type = 'project|locale|set-slug'; 23 | $this->default_conditions = "object_type = '".$this->object_type."'"; 24 | } 25 | 26 | function prepare_fields_for_save( $args ) { 27 | $args = (array)$args; 28 | $args['object_type'] = $this->object_type; 29 | if ( gp_array_get( $args, 'project_id' ) && gp_array_get( $args, 'locale_slug' ) 30 | && gp_array_get( $args, 'set_slug' ) && !gp_array_get( $args, 'object_id' ) ) { 31 | $args['object_id'] = $this->object_id( $args['project_id'], $args['locale_slug'], $args['set_slug'] ); 32 | } 33 | $args = parent::prepare_fields_for_save( $args ); 34 | return $args; 35 | } 36 | 37 | function project_id_locale_slug_set_slug( $object_id ) { 38 | return explode( '|', $object_id ); 39 | } 40 | 41 | function object_id( $project_id, $locale_slug, $set_slug = 'default' ) { 42 | return implode( '|', array( $project_id, $locale_slug, $set_slug ) ); 43 | } 44 | 45 | function by_project_id( $project_id ) { 46 | $project_id = (int)$project_id; 47 | return $this->find_many( "object_id LIKE '$project_id|%'" ); 48 | } 49 | } 50 | GP::$validator_permission = new GP_Validator_Permission(); -------------------------------------------------------------------------------- /gp-includes/cli.php: -------------------------------------------------------------------------------- 1 | program_name = array_shift( $argv ); 21 | $this->options = getopt( $this->short_options, $this->long_options ); 22 | $this->args = $argv; 23 | } 24 | 25 | function usage() { 26 | $this->error( 'php '.$this->program_name.' '.$this->usage ); 27 | } 28 | 29 | function to_stderr( $text, $no_new_line = false ) { 30 | $text .= ($no_new_line? '' : "\n"); 31 | fwrite( STDERR, $text ); 32 | } 33 | 34 | function error( $message, $exit_code = 1 ) { 35 | $this->to_stderr( $message ); 36 | exit( $exit_code ); 37 | } 38 | } 39 | 40 | class GP_Translation_Set_Script extends GP_CLI { 41 | 42 | var $short_options = 'p:l:t:'; 43 | 44 | var $usage = "-p -l [-t ]"; 45 | 46 | function run() { 47 | if ( !isset( $this->options['l'] ) || !isset( $this->options['p'] ) ) { 48 | $this->usage(); 49 | } 50 | $this->project = GP::$project->by_path( $this->options['p'] ); 51 | if ( !$this->project ) $this->error( __('Project not found!') ); 52 | 53 | $this->locale = GP_Locales::by_slug( $this->options['l'] ); 54 | if ( !$this->locale ) $this->error( __('Locale not found!') ); 55 | 56 | $this->options['t'] = gp_array_get( $this->options, 't', 'default' ); 57 | 58 | $this->translation_set = GP::$translation_set->by_project_id_slug_and_locale( $this->project->id, $this->options['t'], $this->locale->slug ); 59 | if ( !$this->translation_set ) $this->error( __('Translation set not found!') ); 60 | 61 | $this->action_on_translation_set( $this->translation_set ); 62 | } 63 | 64 | function action_on_translation_set( $translation_set ) { 65 | // define this function in a subclass 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /gp-includes/formats/format_pomo.php: -------------------------------------------------------------------------------- 1 | class; 12 | // TODO: add more meta data in the project: language team, report URL 13 | $po->set_header( 'PO-Revision-Date', GP::$translation->last_modified( $translation_set ) . '+0000' ); 14 | $po->set_header( 'MIME-Version', '1.0' ); 15 | $po->set_header( 'Content-Type', 'text/plain; charset=UTF-8' ); 16 | $po->set_header( 'Content-Transfer-Encoding', '8bit' ); 17 | $po->set_header( 'Plural-Forms', "nplurals=$locale->nplurals; plural=$locale->plural_expression;" ); 18 | $po->set_header( 'X-Generator', 'GlotPress/' . gp_get_option('version') ); 19 | 20 | // force export only current translations 21 | $filters = array(); 22 | $filters['status'] = 'current'; 23 | 24 | foreach( $entries as $entry ) { 25 | $po->add_entry( $entry ); 26 | } 27 | $po->set_header( 'Project-Id-Version', $project->name ); 28 | 29 | // TODO: include parent project's names in the comment 30 | $po->comments_before_headers .= "Translation of {$project->name} in {$locale->english_name}\n"; 31 | $po->comments_before_headers .= "This file is distributed under the same license as the {$project->name} package.\n"; 32 | 33 | return $po->export(); 34 | } 35 | 36 | public function read_translations_from_file( $file_name, $project = null ) { 37 | $po = new $this->class; 38 | $result = $po->import_from_file( $file_name ); 39 | 40 | return $result ? $po : $result; 41 | } 42 | 43 | public function read_originals_from_file( $file_name ) { 44 | return $this->read_translations_from_file( $file_name ); 45 | } 46 | 47 | } 48 | 49 | class GP_Format_MO extends GP_Format_PO { 50 | public $name = 'Machine Object Message Catalog (.mo)'; 51 | public $extension = 'mo'; 52 | 53 | public $class = 'MO'; 54 | } 55 | 56 | GP::$formats['po'] = new GP_Format_PO; 57 | GP::$formats['mo'] = new GP_Format_MO; -------------------------------------------------------------------------------- /gp-templates/locales.php: -------------------------------------------------------------------------------- 1 | 7 | 8 |

9 |
10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | " . gp_link_get( gp_url_join( gp_url_current(), $locale->slug ), $locale->english_name ) . "" ?> 26 | " . gp_link_get( gp_url_join( gp_url_current(), $locale->slug ), $locale->native_name ) . "" ?> 27 | " . gp_link_get( gp_url_join( gp_url_current(), $locale->slug ), $locale->slug ) . "" ?> 28 | 29 | 30 | 31 |
32 | 33 | 67 | 68 | name ) ); 3 | gp_breadcrumb_project( $project ); 4 | gp_tmpl_header(); 5 | ?> 6 |

name ) ) ); ?>

7 |

8 |
9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 | 17 |
18 |
19 |
20 |
21 |
22 | 23 | %file% and %line%. Ex. https://trac.example.org/browser/%file%#L%line%'); ?> 24 |
25 |
26 | 27 |

28 |
29 | 30 | request( $uri, 'GET', $get_vars ); 8 | } 9 | 10 | function post( $uri, $get_vars = array() ) { 11 | $this->request( $uri, 'POST', $get_vars ); 12 | } 13 | 14 | private function request( $uri, $method, $vars ) { 15 | $tmp_file_name = tempnam( sys_get_temp_dir(), 'gp-test-request-config' ); 16 | if ( !$tmp_file_name) { 17 | return false; 18 | } 19 | $config_vars = array( 20 | 'upper_method' => strtoupper( $method ), 21 | 'vars' => $vars, 22 | 'uri' => $uri, 23 | 'gp_config_path' => dirname( __FILE__ ) . '/../unittests-config.php', 24 | ); 25 | extract( array_map( create_function( '$value', 'return var_export( $value, true );' ), $config_vars ) ); 26 | $config_php_code = <<body = ob_get_contents(); 40 | ob_end_clean(); 41 | } 42 | 43 | function assertRedirect() { 44 | $this->assertTrue( gp_startswith( $this->body, 'Redirecting to: ') ); 45 | } 46 | 47 | function assertResponseContains( $needle ) { 48 | $this->assertTrue( gp_in( $needle, $this->body ) ); 49 | } 50 | 51 | function assertResponseNotContains( $needle ) { 52 | $this->assertFalse( gp_in( $needle, $this->body ) ); 53 | } 54 | } -------------------------------------------------------------------------------- /js/common.js: -------------------------------------------------------------------------------- 1 | var $gp = function($) { return { 2 | notices: { 3 | element: null, 4 | init: function() { 5 | $gp.notices.element = $('#gp-js-message'); 6 | }, 7 | error: function(message) { 8 | $gp.notices.generic_message('gp-js-error', message); 9 | }, 10 | notice: function(message) { 11 | $gp.notices.generic_message('gp-js-notice', message); 12 | }, 13 | success: function(message) { 14 | $gp.notices.generic_message('gp-js-success', message); 15 | $gp.notices.element.fadeOut(10000); 16 | }, 17 | clear: function(message) { 18 | $gp.notices.element.html('').hide(); 19 | }, 20 | generic_message: function(css_class, message) { 21 | // TODO: add close button, at least to errors 22 | $gp.notices.element.removeClass().addClass(css_class).html(message); 23 | $gp.notices.center(); 24 | $gp.notices.element.show(); 25 | }, 26 | center: function() { 27 | $gp.notices.element.css('left', ($(document).width() - $gp.notices.element.width()) / 2); 28 | } 29 | }, 30 | esc_html: function(s) { 31 | return $('
').text(s).html(); 32 | }, 33 | init: function() { 34 | $gp.notices.init(); 35 | } 36 | }}(jQuery); 37 | 38 | $gp.showhide = function($) { return function(link, container, options) { 39 | var defaults= { 40 | show_text: 'Show', 41 | hide_text: 'Hide', 42 | focus: false, 43 | group: 'default' 44 | } 45 | var options = $.extend({}, defaults, options); 46 | var $link = $(link); 47 | var $container = $(container); 48 | if ( !$gp.showhide.registry[options.group] ) $gp.showhide.registry[options.group] = []; 49 | var registry = $gp.showhide.registry[options.group]; 50 | var show = function() { 51 | for(var i = 0; i < registry.length; ++i) { 52 | registry[i].hide(); 53 | } 54 | $container.show(); 55 | if (options.focus) $(options.focus, $container).focus(); 56 | $link.html(options.hide_text).addClass('open'); 57 | } 58 | var hide = function() { 59 | $container.hide(); 60 | $link.html(options.show_text).removeClass('open'); 61 | } 62 | registry.push({show: show, hide: hide}); 63 | $link.click(function() { 64 | $container.is(':visible')? hide() : show(); 65 | return false; 66 | }) 67 | }}(jQuery); 68 | $gp.showhide.registry = {}; 69 | -------------------------------------------------------------------------------- /scripts/import-originals.php: -------------------------------------------------------------------------------- 1 | -f [-o ] [--disable-propagating] [--disable-matching]"; 13 | 14 | function run() { 15 | if ( !isset( $this->options['p'] ) ) { 16 | $this->usage(); 17 | } 18 | 19 | $project = GP::$project->by_path( $this->options['p'] ); 20 | if ( !$project ) $this->error( __('Project not found!') ); 21 | 22 | $format = gp_array_get( GP::$formats, isset( $this->options['o'] )? $this->options['o'] : 'po', null ); 23 | if ( !$format ) $this->error( __('No such format.') );; 24 | 25 | $translations = $format->read_originals_from_file( $this->options['f'], $project ); 26 | if ( !$translations ) { 27 | $this->error( __("Couldn't load translations from file!") ); 28 | } 29 | 30 | $disable_propagating = isset( $this->options['disable-propagating'] ); 31 | $disable_matching = isset( $this->options['disable-matching'] ); 32 | 33 | if ( $disable_propagating ) { 34 | add_filter( 'enable_propagate_translations_across_projects', '__return_false' ); 35 | } 36 | if ( $disable_matching ) { 37 | add_filter( 'enable_add_translations_from_other_projects', '__return_false' ); 38 | } 39 | 40 | list( $originals_added, $originals_existing, $originals_fuzzied, $originals_obsoleted ) = GP::$original->import_for_project( $project, $translations ); 41 | 42 | if ( $disable_matching ) { 43 | remove_filter( 'enable_add_translations_from_other_projects', '__return_false' ); 44 | } 45 | if ( $disable_propagating ) { 46 | remove_filter( 'enable_propagate_translations_across_projects', '__return_false' ); 47 | } 48 | 49 | printf( 50 | __( '%1$s new strings added, %2$s updated, %3$s fuzzied, and %4$s obsoleted.' ), 51 | $originals_added, 52 | $originals_existing, 53 | $originals_fuzzied, 54 | $originals_obsoleted 55 | ); 56 | echo "\n"; 57 | } 58 | } 59 | 60 | $gp_script_import_originals = new GP_Script_Import_Originals; 61 | $gp_script_import_originals->run(); 62 | -------------------------------------------------------------------------------- /gp-includes/backpress/class.bp-roles.php: -------------------------------------------------------------------------------- 1 | __construct(); 9 | } 10 | 11 | function __construct() { 12 | do_action_ref_array('init_roles', array(&$this) ); 13 | } 14 | 15 | function add_role($role, $display_name, $capabilities = '') { 16 | if ( isset($this->role_objects[$role]) ) 17 | return; 18 | 19 | $this->role_objects[$role] = new BP_Role($role, $capabilities, $this); 20 | $this->role_names[$role] = $display_name; 21 | return $this->role_objects[$role]; 22 | } 23 | 24 | function remove_role($role) { 25 | if ( ! isset($this->role_objects[$role]) ) 26 | return; 27 | 28 | unset($this->role_objects[$role]); 29 | unset($this->role_names[$role]); 30 | } 31 | 32 | function add_cap($role, $cap, $grant = true) { 33 | if ( isset($this->role_objects[$role]) ) 34 | $this->role_objects[$role]->add_cap($cap, $grant); 35 | } 36 | 37 | function remove_cap($role, $cap) { 38 | if ( isset($this->role_objects[$role]) ) 39 | $this->role_objects[$role]->remove_cap($cap, $grant); 40 | } 41 | 42 | function &get_role($role) { 43 | if ( isset($this->role_objects[$role]) ) 44 | return $this->role_objects[$role]; 45 | else 46 | return null; 47 | } 48 | 49 | function get_names() { 50 | return $this->role_names; 51 | } 52 | 53 | function is_role($role) { 54 | return isset($this->role_names[$role]); 55 | } 56 | 57 | function map_meta_cap( $cap, $user_id ) { 58 | $args = array_slice(func_get_args(), 2); 59 | return apply_filters( 'map_meta_cap', array( $cap ), $cap, $user_id, $args ); 60 | } 61 | } 62 | 63 | class BP_Role { 64 | var $name; 65 | var $capabilities; 66 | 67 | function BP_Role($role, $capabilities) { 68 | $this->name = $role; 69 | $this->capabilities = $capabilities; 70 | } 71 | 72 | function add_cap($cap, $grant = true) { 73 | $this->capabilities[$cap] = $grant; 74 | } 75 | 76 | function remove_cap($cap) { 77 | unset($this->capabilities[$cap]); 78 | } 79 | 80 | function has_cap($cap) { 81 | $capabilities = apply_filters('role_has_cap', $this->capabilities, $cap, $this->name); 82 | $grant = !empty( $capabilities[$cap] ); 83 | return apply_filters("{$this->name}_has_cap", $grant); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /gp-templates/profile-public.php: -------------------------------------------------------------------------------- 1 | 7 | 8 |

display_name; ?> admin() ) { _e('(Admin)'); }; ?>

9 | 10 |
11 |
12 |
13 | 14 | 27 |
28 |
29 | 30 |
31 |
32 |

33 | 34 |
    35 | 36 |
  • 37 |

    project_url, $project->set_name ) . ': '; 39 | echo gp_link_get( $project->project_url . '?filters[status]=either&filters[user_login]=' . $user->user_login, 40 | sprintf( _n( '%s contribution', '%s contributions',$project->count ), $project->count ) ); 41 | ?>

    42 |

    43 | last_updated ) ) ); ?> 44 |

    45 |
  • 46 | 47 |
48 |
49 |
50 |

51 | 52 | = 1 ): ?> 53 |
    54 | 55 |
  • 56 |

    project_url, $permission->set_name ); ?>

    57 |
  • 58 | 59 |
60 | 61 |

display_name )?>

62 | 63 |
64 |
65 | 66 | mytable = 'mytable'; 14 | $this->t = new GP_My_Table; 15 | } 16 | 17 | function test_sql_condition_from_php_value() { 18 | $this->assertEquals( '= 5', $this->t->sql_condition_from_php_value( 5 ) ); 19 | $this->assertEquals( '= 5', $this->t->sql_condition_from_php_value( '5' ) ); 20 | $this->assertEquals( "= 'baba'", $this->t->sql_condition_from_php_value( 'baba' ) ); 21 | $this->assertEquals( "IS NULL", $this->t->sql_condition_from_php_value( null ) ); 22 | $this->assertEquals( array('= 5', '= 10'), $this->t->sql_condition_from_php_value( array( 5, 10 ) ) ); 23 | $this->assertEquals( array("= 'baba'", "= 10", "= 'don\\'t'"), $this->t->sql_condition_from_php_value( array( 'baba', '10', "don't" ) ) ); 24 | } 25 | 26 | function test_sql_from_conditions() { 27 | $this->assertEquals( 'a = 5', $this->t->sql_from_conditions( array('a' => 5) ) ); 28 | $this->assertEquals( "(a = 5 OR a = 6) AND b = 'baba'", $this->t->sql_from_conditions( array('a' => array(5, 6), 'b' => 'baba' ) ) ); 29 | } 30 | 31 | function test_sql_from_order() { 32 | $this->assertEquals( '', $this->t->sql_from_order( null ) ); 33 | $this->assertEquals( '', $this->t->sql_from_order( '' ) ); 34 | $this->assertEquals( '', $this->t->sql_from_order( array() ) ); 35 | $this->assertEquals( '', $this->t->sql_from_order( array(), 'baba' ) ); 36 | $this->assertEquals( 'ORDER BY x', $this->t->sql_from_order( 'x' ) ); 37 | $this->assertEquals( 'ORDER BY table.field', $this->t->sql_from_order( 'table.field' ) ); 38 | $this->assertEquals( 'ORDER BY table.field ASC', $this->t->sql_from_order( 'table.field ASC' ) ); 39 | $this->assertEquals( 'ORDER BY table.field', $this->t->sql_from_order( array( 'table.field' ) ) ); 40 | $this->assertEquals( 'ORDER BY table.field ASC', $this->t->sql_from_order( 'table.field', 'ASC' ) ); 41 | $this->assertEquals( 'ORDER BY table.field ASC', $this->t->sql_from_order( array( 'table.field', 'ASC' ) ) ); 42 | $this->assertEquals( 'ORDER BY table.field ASC', $this->t->sql_from_order( array( 'table.field', 'ASC' ), 'baba' ) ); 43 | } 44 | } -------------------------------------------------------------------------------- /t/tests/tests_things/test_thing_glossary_entry.php: -------------------------------------------------------------------------------- 1 | create( array( 'glossary_id' => '', 'term' => 'term', 'part_of_speech' => 'verb', 'last_edited_by' =>'1' ) ); 7 | $verdict = $glossary_entry->validate(); 8 | 9 | $this->assertFalse( $verdict ); 10 | } 11 | 12 | function test_empty_term() { 13 | $glossary_entry = GP::$glossary_entry->create( array( 'glossary_id' => '1', 'term' => '', 'part_of_speech' => 'verb', 'last_edited_by' =>'1' ) ); 14 | $verdict = $glossary_entry->validate(); 15 | 16 | $this->assertFalse( $verdict ); 17 | } 18 | 19 | function test_empty_part_of_speech() { 20 | $glossary_entry = GP::$glossary_entry->create( array( 'glossary_id' => '1', 'term' => 'term', 'part_of_speech' => '', 'last_edited_by' =>'1' ) ); 21 | $verdict = $glossary_entry->validate(); 22 | 23 | $this->assertFalse( $verdict ); 24 | } 25 | 26 | function test_negative_last_edited_by() { 27 | $glossary_entry = GP::$glossary_entry->create( array( 'glossary_id' => '1', 'term' => 'tern', 'part_of_speech' => 'verb', 'last_edited_by' =>'-1' ) ); 28 | $verdict = $glossary_entry->validate(); 29 | 30 | $this->assertFalse( $verdict ); 31 | } 32 | 33 | function test_empty_last_edited_by() { 34 | $glossary_entry = GP::$glossary_entry->create( array( 'glossary_id' => '1', 'term' => 'tern', 'part_of_speech' => 'verb', 'last_edited_by' =>'0' ) ); 35 | $verdict = $glossary_entry->validate(); 36 | 37 | $this->assertFalse( $verdict ); 38 | } 39 | 40 | function test_by_glossary_id() { 41 | $glossary_entry_1 = GP::$glossary_entry->create( array( 'glossary_id' => '1', 'term' => 'term', 'part_of_speech' => 'verb', 'last_edited_by' =>'1' ) ); 42 | $glossary_entry_2 = GP::$glossary_entry->create( array( 'glossary_id' => '2', 'term' => 'term', 'part_of_speech' => 'verb', 'last_edited_by' =>'1' ) ); 43 | $new = GP::$glossary_entry->by_glossary_id( '1' ); 44 | $this->assertEquals( array( $glossary_entry_1 ), $new ); 45 | $this->assertNotEquals( array( $glossary_entry_2 ), $new ); 46 | } 47 | 48 | function test_part_of_speech_array_set() { 49 | $this->assertCount( 9, GP::$glossary_entry->parts_of_speech ); 50 | $this->assertArrayHasKey( 'noun', GP::$glossary_entry->parts_of_speech ); 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /css/install.css: -------------------------------------------------------------------------------- 1 | p, li, dd, dt { 2 | padding-bottom: 2px; 3 | font-size: 14px; 4 | line-height: 1.5; 5 | } 6 | 7 | ul, ol, dl { 8 | padding: 5px 5px 5px 22px; 9 | } 10 | 11 | abbr { 12 | border: 0; 13 | font-variant: normal; 14 | } 15 | .step { 16 | margin: 20px 0 15px; 17 | } 18 | .step, th { 19 | text-align: left; 20 | padding: 0; 21 | } 22 | .step .button-large { 23 | font-size: 14px; 24 | } 25 | textarea { 26 | border: 1px solid #dfdfdf; 27 | font-family: "Open Sans", sans-serif; 28 | width: 100%; 29 | -webkit-box-sizing: border-box; 30 | -moz-box-sizing: border-box; 31 | box-sizing: border-box; 32 | } 33 | 34 | .form-table { 35 | border-collapse: collapse; 36 | margin-top: 1em; 37 | width: 100%; 38 | } 39 | 40 | .form-table td { 41 | margin-bottom: 9px; 42 | padding: 10px 20px 10px 0; 43 | border-bottom: 8px solid #fff; 44 | font-size: 14px; 45 | vertical-align: top; 46 | } 47 | 48 | .form-table th { 49 | font-size: 14px; 50 | text-align: left; 51 | padding: 16px 20px 10px 0; 52 | width: 140px; 53 | vertical-align: top; 54 | } 55 | 56 | .form-table code { 57 | line-height: 18px; 58 | font-size: 14px; 59 | } 60 | 61 | .form-table p { 62 | margin: 4px 0 0 0; 63 | font-size: 11px; 64 | } 65 | 66 | .form-table input { 67 | line-height: 20px; 68 | font-size: 15px; 69 | padding: 3px 5px; 70 | border: 1px solid #ddd; 71 | -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,0.07); 72 | box-shadow: inset 0 1px 2px rgba(0,0,0,0.07); 73 | } 74 | 75 | .form-table input[type=text], 76 | .form-table input[type=password] { 77 | width: 206px; 78 | } 79 | 80 | .form-table th p { 81 | font-weight: normal; 82 | } 83 | 84 | .form-table.install-success td { 85 | vertical-align: middle; 86 | padding: 16px 20px 10px 0; 87 | } 88 | 89 | .form-table.install-success td p { 90 | margin: 0; 91 | font-size: 14px; 92 | } 93 | 94 | .form-table.install-success td code { 95 | margin: 0; 96 | font-size: 18px; 97 | } 98 | 99 | .message { 100 | border: 1px solid #c00; 101 | padding: 0.5em 0.7em; 102 | margin: 5px 0 15px; 103 | background-color: #ffebe8; 104 | } 105 | 106 | .form-table td input[type="password"] { 107 | line-height: 1.5; 108 | display: block; 109 | -webkit-box-sizing: border-box; 110 | -moz-box-sizing: border-box; 111 | box-sizing: border-box; 112 | } -------------------------------------------------------------------------------- /t/lib/testcase-route.php: -------------------------------------------------------------------------------- 1 | route = new $this->route_class; 10 | $this->route->fake_request = true; 11 | $this->route->errors = array(); 12 | $this->route->notices = array(); 13 | } 14 | 15 | function assertRedirected() { 16 | $this->assertTrue( $this->route->redirected, "Wasn't redirected" ); 17 | } 18 | 19 | function assertRedirectURLContains( $text ) { 20 | $this->assertRedirected(); 21 | $this->assertContains( $text, $this->route->redirected_to ); 22 | } 23 | 24 | function assertThereIsAnErrorContaining( $text ) { 25 | $this->assertThereIsAnArrayElementContaining( $text, $this->route->errors, "No error contains '$text'" ); 26 | } 27 | 28 | function assertThereIsANoticeContaining( $text ) { 29 | $this->assertThereIsAnArrayElementContaining( $text, $this->route->notices, "No notice contains '$text'" ); 30 | } 31 | 32 | function assertThereIsAnArrayElementContaining( $text, $array, $message = null ) { 33 | $this->assertGreaterThan( 0, count( $array ), 'The array is empty.' ); 34 | $message = $message? $message : "No array element contains '$text'"; 35 | 36 | $this->assertTrue( gp_array_any( function( $e ) use ( $text) { return gp_in( $text, $e ); }, $array ), $message ); 37 | } 38 | 39 | function assertNotAllowedRedirect() { 40 | $this->assertRedirected(); 41 | $this->assertThereIsAnErrorContaining( 'allowed' ); 42 | } 43 | 44 | function assertInvalidRedirect() { 45 | $this->assertRedirected(); 46 | $this->assertThereIsAnErrorContaining( 'invalid' ); 47 | } 48 | 49 | function assertErrorRedirect() { 50 | $this->assertRedirected(); 51 | $this->assertThereIsAnErrorContaining( 'Error' ); 52 | } 53 | 54 | function assertTemplateLoadedIs( $template ) { 55 | $this->assertTrue( $this->route->rendered_template, "No template was rendered" ); 56 | $this->assertEquals( $template, $this->route->loaded_template ); 57 | } 58 | 59 | function assertTemplateOutputNotEmpty() { 60 | $this->assertFalse( empty( $this->route->template_output ), "Template output is empty" ); 61 | } 62 | 63 | function assert404() { 64 | $this->assertTemplateLoadedIs( '404' ); 65 | } 66 | 67 | /** 68 | * Parses and returns the API response. 69 | */ 70 | function api_response() { 71 | return json_decode( $this->route->template_output ); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /gp-includes/advanced-permissions.php: -------------------------------------------------------------------------------- 1 | get( $args['object_id'] ); 12 | if ( $project->parent_project_id ) { 13 | return $args['user']->can( $args['action'], 'project', $project->parent_project_id ); 14 | } 15 | return false; 16 | } 17 | 18 | function gp_recurse_validator_permission( $verdict, $args ) { 19 | if ( !( !$verdict && $args['object_type'] == GP::$validator_permission->object_type && $args['object_id'] && $args['user'] ) ) { 20 | return $verdict; 21 | } 22 | list( $project_id, $locale_slug, $set_slug ) = GP::$validator_permission->project_id_locale_slug_set_slug( $args['object_id'] ); 23 | $project = GP::$project->get( $project_id ); 24 | if ( $project->parent_project_id ) { 25 | return $args['user']->can( $args['action'], $args['object_type'], $project->parent_project_id.'|'.$locale_slug.'|'.$set_slug ); 26 | } 27 | return false; 28 | } 29 | 30 | 31 | function gp_route_translation_set_permissions_to_validator_permissions( $verdict, $args ) { 32 | if ( !( $verdict == 'no-verdict' && $args['action'] == 'approve' && $args['object_type'] == 'translation-set' 33 | && $args['object_id'] && $args['user'] ) ) { 34 | return $verdict; 35 | } 36 | if ( isset( $args['extra']['set'] ) && $args['extra']['set'] && $args['extra']['set']->id == $args['object_id'] ) 37 | $set = $args['extra']['set']; 38 | else 39 | $set = GP::$translation_set->get( $args['object_id'] ); 40 | return $args['user']->can( 'approve', GP::$validator_permission->object_type, 41 | GP::$validator_permission->object_id( $set->project_id, $set->locale, $set->slug ) ); 42 | } 43 | 44 | function gp_allow_everyone_to_translate( $verdict, $args ) { 45 | if ( 'edit' == $args['action'] && 'translation-set' == $args['object_type'] ) { 46 | return GP::$user->logged_in(); 47 | } 48 | 49 | return $verdict; 50 | } 51 | 52 | add_filter( 'can_user', 'gp_recurse_project_permissions', 10, 2 ); 53 | add_filter( 'can_user', 'gp_recurse_validator_permission', 10, 2 ); 54 | add_filter( 'pre_can_user', 'gp_route_translation_set_permissions_to_validator_permissions', 10, 2 ); 55 | add_filter( 'pre_can_user', 'gp_allow_everyone_to_translate', 10, 2 ); 56 | -------------------------------------------------------------------------------- /plugins/google-translate/google-translate.js: -------------------------------------------------------------------------------- 1 | $gp.google_translate = function($){ return { 2 | current: null, 3 | init: function(table) { 4 | $gp.init(); 5 | $gp.google_translate.table = table; 6 | $gp.google_translate.install_hooks(); 7 | }, 8 | install_hooks: function() { 9 | $($gp.google_translate.table).on('click', 'a.gtranslate', $gp.google_translate.hooks.google_translate) 10 | }, 11 | google_translate: function(link) { 12 | original_text = link.parents('.textareas').siblings('.original').text(); 13 | if (!original_text) original_text = link.parents('.textareas').siblings('p:last').children('.original').html(); 14 | if (!original_text) return; 15 | 16 | $gp.notices.notice('Translating via Google Translate…'); 17 | 18 | var url = 'https://www.googleapis.com/language/translate/v2?key=' + gp_google_translate.key + '&q=' + original_text + '&source=en&target=' + gp_google_translate.locale; 19 | 20 | $.getJSON( url, function(result) { 21 | if (!result.error) { 22 | var translated_text = result.data.translations[0].translatedText; 23 | 24 | // fix common google translate misbehaviours 25 | translated_text = translated_text.replace(/% (s|d)/gi, function(m, letter) { 26 | return '%'+letter.toLowerCase(); 27 | }); 28 | translated_text = translated_text.replace(/% (\d+) \$ (S|D)/gi, function(m, number, letter) { 29 | return '%'+number+'$'+letter.toLowerCase(); 30 | }); 31 | translated_text = translated_text.replace(/<\/\s+([A-Z]+)>/g, function(m, tag) { 32 | return '</'+tag.toLowerCase()+'>'; 33 | }); 34 | 35 | link.parent('p').siblings('textarea').html(translated_text).focus(); 36 | $gp.notices.success('Translated!'); 37 | } 38 | else { 39 | $gp.notices.error('Error in translating via Google Translate: ' + result.error.message + ': ' + result.error.reason + ''); 40 | link.parent('p').siblings('textarea').focus(); 41 | } 42 | }).fail(function( jqxhr, textStatus, error ) { 43 | var result = jQuery.parseJSON( jqxhr.responseText ); 44 | 45 | $gp.notices.error('Error in translating via Google Translate: ' + result.error.message ); 46 | link.parent('p').siblings('textarea').focus(); 47 | }); 48 | }, 49 | hooks: { 50 | google_translate: function() { 51 | $gp.google_translate.google_translate($(this)); 52 | return false; 53 | } 54 | } 55 | }}(jQuery); 56 | 57 | if (typeof google != 'undefined') google.load("language", "1"); 58 | 59 | jQuery(function($) { 60 | $gp.google_translate.init($('#translations')); 61 | }); 62 | -------------------------------------------------------------------------------- /gp-config-sample.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | '; 15 | echo implode( "\n", $errors ); 16 | echo ''; 17 | } 18 | else if ( isset( $success_message ) ) { 19 | echo '

' . $success_message . '

'; 20 | } 21 | ?> 22 | 23 | 26 |

27 | .htaccess file were writable, we could do this automatically, but it isn’t so these are the mod_rewrite rules you should have in your .htaccess file.' ); ?> 28 | 29 |

30 |

31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | 42 | 43 | 44 | 48 | 53 | 54 | 55 | 56 | 58 | 59 |
39 | 40 |

41 |
45 | 46 |

47 |
49 | 50 | 51 |

52 |
57 |

60 |

61 |
62 | 63 | 64 | set_admin_user_as_current(); 12 | 13 | $set1 = $this->factory->translation_set->create_with_project_and_locale( array( 'locale' => 'bg' ), array( 'name' => 'project_one' ) ); 14 | 15 | $project2 = $this->factory->project->create( array( 'name'=>'project_two' ) ); 16 | $set2 = $this->factory->translation_set->create( array( 'locale' => $set1->locale, 'project_id' => $project2->id ) ); 17 | 18 | $original1 = $this->factory->original->create( array( 'project_id' => $set1->project_id, 'status' => '+active', 'singular' => 'baba' ) ); 19 | $original2 = $this->factory->original->create( array( 'project_id' => $set2->project_id, 'status' => '+active', 'singular' => 'baba' ) ); 20 | 21 | // Create a translation with two warnings 22 | $warnings = array( 23 | 0 => array( 'placeholder' => 'Missing %2$s placeholder in translation.' ), 24 | 1 => array( 'should_begin_on_newline' => 'Original and translation should both begin on newline.' ), 25 | ); 26 | $translation1 = $this->factory->translation->create( array( 'translation_set_id' => $set1->id, 'original_id' => $original1->id, 'status' => 'current', 'warnings' => $warnings ) ); 27 | $translation1->set_as_current(); //calls propagate_across_projects 28 | 29 | // Second original shouldn't translated yet because of two warnings. 30 | $set2_current_translations = GP::$translation->for_export( $project2, $set2, array( 'status' => 'current' ) ); 31 | $this->assertEquals( 0, count( $set2_current_translations ) ); 32 | 33 | $_POST['translation_id'] = $translation1->id; 34 | $_POST['index'] = 0; 35 | $_POST['key'] = 'placeholder'; 36 | $this->route->discard_warning( $project2->path, $set2->locale, $set2->slug ); 37 | 38 | // Second original shouldn't translated yet because of one warning. 39 | $set2_current_translations = GP::$translation->for_export( $project2, $set2, array( 'status' => 'current' ) ); 40 | $this->assertEquals( 0, count( $set2_current_translations ) ); 41 | 42 | $_POST['translation_id'] = $translation1->id; 43 | $_POST['index'] = 1; 44 | $_POST['key'] = 'should_begin_on_newline'; 45 | $this->route->discard_warning( $project2->path, $set2->locale, $set2->slug ); 46 | 47 | // Second original should be translated now. 48 | $set2_current_translations = GP::$translation->for_export( $project2, $set2, array( 'status' => 'current' ) ); 49 | $this->assertEquals( 1, count( $set2_current_translations ) ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /gp-includes/things/glossary.php: -------------------------------------------------------------------------------- 1 | translation_set_id_should_not_be('empty'); 11 | } 12 | 13 | /** 14 | * Get the path to the glossary. 15 | * 16 | * @return string 17 | */ 18 | public function path() { 19 | $translation_set = GP::$translation_set->get( $this->translation_set_id ); 20 | $project = GP::$project->get( $translation_set->project_id ); 21 | 22 | return gp_url_join( gp_url_project_locale( $project->path, $translation_set->locale, $translation_set->slug ), 'glossary' ); 23 | } 24 | 25 | /** 26 | * Get the glossary by set/project. 27 | * If there's no glossary for this specific project, get the nearest parent glossary 28 | * 29 | * @param GP_Project $project 30 | * @param GP_Translation_Set $translation_set 31 | * 32 | * @return GP_Glossary 33 | */ 34 | public function by_set_or_parent_project( $translation_set, $project ) { 35 | $glossary = $this->by_set_id( $translation_set->id ); 36 | 37 | if ( ! $glossary && $project->parent_project_id ) { 38 | $locale = $translation_set->locale; 39 | $slug = $translation_set->slug; 40 | 41 | while ( ! $glossary && $project->parent_project_id ) { 42 | $project = GP::$project->get( $project->parent_project_id ); 43 | $translation_set = GP::$translation_set->by_project_id_slug_and_locale( $project->id, $slug, $locale ); 44 | 45 | if ( $translation_set ) { 46 | $glossary = $this->by_set_id( $translation_set->id ); 47 | } 48 | } 49 | } 50 | 51 | return $glossary; 52 | } 53 | 54 | function by_set_id( $set_id ) { 55 | return $this->one( " 56 | SELECT * FROM $this->table 57 | WHERE translation_set_id = %d LIMIT 1", $set_id ); 58 | } 59 | 60 | 61 | /** 62 | * Copies glossary items from a glossary to the current one 63 | * This function does not merge then, just copies unconditionally. If a translation already exists, it will be duplicated. 64 | * 65 | * @param int $source_glossary_id 66 | * 67 | * @return mixed 68 | */ 69 | function copy_glossary_items_from( $source_glossary_id ) { 70 | global $gpdb; 71 | 72 | $current_date = $this->now_in_mysql_format(); 73 | 74 | return $this->query(" 75 | INSERT INTO $gpdb->glossary_items ( 76 | id, term, type, examples, comment, suggested_translation, last_update 77 | ) 78 | SELECT 79 | %s AS id, term, type, examples, comment, suggested_translation, %s AS last_update 80 | FROM $gpdb->glossary_items WHERE id = %s", $this->id, $current_date, $source_glossary_id 81 | ); 82 | } 83 | 84 | } 85 | 86 | GP::$glossary = new GP_Glossary(); -------------------------------------------------------------------------------- /t/tests/test_user.php: -------------------------------------------------------------------------------- 1 | factory->user->create(); 7 | $set_1_permission = array( 'user_id' => $user->id, 'action' => 'write', 'object_type' => 'translation-set', 'object_id' => 1 ); 8 | GP::$permission->create( $set_1_permission ); 9 | $this->assertTrue( $user->can( 'write', 'translation-set', 1 ) ); 10 | $this->assertFalse( $user->can( 'write', 'translation-set', 2 ) ); 11 | $this->assertFalse( $user->can( 'write', 'translation-set' ) ); 12 | $this->assertFalse( $user->can( 'write' ) ); 13 | } 14 | 15 | function test_admin_should_be_admin() { 16 | $admin_user = $this->factory->user->create_admin(); 17 | $this->assertTrue( $admin_user->admin() ); 18 | } 19 | 20 | function test_non_admin_user_should_not_be_admin() { 21 | $nonadmin_user = $this->factory->user->create(); 22 | $this->assertFalse( $nonadmin_user->admin() ); 23 | } 24 | 25 | function test_admin_should_be_able_to_do_random_actions() { 26 | $admin_user = $this->factory->user->create_admin(); 27 | $this->assertTrue( $admin_user->can( 'milk', 'a cow' ) ); 28 | $this->assertTrue( $admin_user->can( 'milk', 'a cow', 5 ) ); 29 | } 30 | 31 | function test_non_admin_should_not_be_able_to_do_random_actions() { 32 | $nonadmin_user = $this->factory->user->create(); 33 | $this->assertFalse( $nonadmin_user->can( 'milk', 'a cow' ) ); 34 | $this->assertFalse( $nonadmin_user->can( 'milk', 'a cow', 5 ) ); 35 | } 36 | 37 | function test_select_by_login() { 38 | $user = $this->factory->user->create( array( 'user_login' => 'pijo' ) ); 39 | $from_db = GP::$user->by_login( 'pijo' ); 40 | $this->assertEquals( $user->id, $from_db->id ); 41 | } 42 | 43 | function test_select_by_email() { 44 | $user = $this->factory->user->create( array( 'user_login' => 'pijo', 'user_email' => 'pijo@glotpress.org' ) ); 45 | $from_db = GP::$user->by_email( 'pijo@glotpress.org' ); 46 | $this->assertEquals( $user->id, $from_db->id ); 47 | } 48 | 49 | function test_get() { 50 | $user = $this->factory->user->create(); 51 | $from_db = GP::$user->get( $user ); 52 | $this->assertEquals( $user->id, $from_db->id ); 53 | } 54 | 55 | function test_set_meta_should_set_meta() { 56 | $user = $this->factory->user->create(); 57 | $user->set_meta( 'int', 5 ); 58 | $this->assertEquals( 5, $user->get_meta( 'int') ); 59 | } 60 | 61 | function test_delete_meta_should_delete_the_meta() { 62 | $user = $this->factory->user->create(); 63 | $user->set_meta( 'int', 5 ); 64 | $user->delete_meta( 'int' ); 65 | $this->assertEquals( null, $user->get_meta( 'int') ); 66 | } 67 | 68 | function test_setting_array_value_as_meta_should_come_out_as_an_array() { 69 | $user = $this->factory->user->create(); 70 | $user->set_meta( 'mixed', array(1, 2, 3) ); 71 | $this->assertEquals( array(1, 2, 3), $user->get_meta( 'mixed' ) ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /gp-includes/backpress/pomo/entry.php: -------------------------------------------------------------------------------- 1 | $value) { 50 | $this->$varname = $value; 51 | } 52 | if (isset($args['plural']) && $args['plural']) $this->is_plural = true; 53 | if (!is_array($this->translations)) $this->translations = array(); 54 | if (!is_array($this->references)) $this->references = array(); 55 | if (!is_array($this->flags)) $this->flags = array(); 56 | } 57 | 58 | /** 59 | * Generates a unique key for this entry 60 | * 61 | * @return string|bool the key or false if the entry is empty 62 | */ 63 | function key() { 64 | if (!$this->singular) return false; 65 | // prepend context and EOT, like in MO files 66 | return !$this->context? $this->singular : $this->context.chr(4).$this->singular; 67 | } 68 | 69 | function merge_with(&$other) { 70 | $this->flags = array_unique( array_merge( $this->flags, $other->flags ) ); 71 | $this->references = array_unique( array_merge( $this->references, $other->references ) ); 72 | if ( $this->extracted_comments != $other->extracted_comments ) { 73 | $this->extracted_comments .= $other->extracted_comments; 74 | } 75 | 76 | } 77 | } 78 | endif; 79 | -------------------------------------------------------------------------------- /t/tests/test_format_android.php: -------------------------------------------------------------------------------- 1 | android = new GP_Format_Android; 7 | $this->entries = array( 8 | array( 'normal_string', 'Normal String', 'Just A Normal String', '' ), 9 | array( 'with_a_quote', 'I\'m with a quote', 'I\'m with a quote', '' ), 10 | array( 'with_newlines', "new\nlines", "I\nhave\nnew\nlines", '' ), 11 | array( 'with_doublequotes', 'double "quotes"', 'I have double "quotes"', '' ), 12 | array( 'with_utf8', 'питка', 'баба ми омеси питка', '' ), 13 | array( 'with_lt', 'you < me', 'ти < аз', '' ), 14 | array( 'with_gt', 'me > you', "аз > ти", '' ), 15 | array( 'with_amps', 'me & you are not &', 'аз & ти не сме &', '' ), 16 | array( 'with_comment', 'baba', 'баба', 'Me, myself & Irene' ), 17 | ); 18 | } 19 | 20 | function test_export() { 21 | $entries_for_export = array(); 22 | foreach( $this->entries as $sample ) { 23 | list( $context, $original, $translation ) = $sample; 24 | $entries_for_export[] = (object)array( 25 | 'context' => $context, 26 | 'singular' => $original, 27 | 'translations' => array($translation), 28 | ); 29 | } 30 | $this->assertEquals( file_get_contents( 'data/translation.android.xml' ), $this->android->print_exported_file( 'p', 'l', 't', $entries_for_export ) ); 31 | } 32 | 33 | 34 | function test_read_originals() { 35 | $translations = $this->android->read_originals_from_file( 'data/originals.android.xml' ); 36 | 37 | foreach( $this->entries as $sample ) { 38 | list( $context, $original, $translation, $comment ) = $sample; 39 | $translatable_entry = new Translation_Entry( array('singular' => $original, 'context' => $context) ); 40 | $entry = $translations->translate_entry( $translatable_entry ); 41 | $this->assertEquals( $original, $entry->singular ); 42 | $this->assertEquals( $context, $entry->context ); 43 | $this->assertEquals( $comment, $entry->extracted_comments ); 44 | } 45 | } 46 | 47 | function test_read_translations() { 48 | $stubbed_originals = array(); 49 | foreach( $this->entries as $sample ) { 50 | list( $context, $original, $translation ) = $sample; 51 | $stubbed_originals[] = new GP_Original( array( 'singular' => $original, 'context' => $context ) ); 52 | } 53 | GP::$original = $this->getMock( 'GP_Original', array('by_project_id') ); 54 | GP::$original->expects( $this->once() ) 55 | ->method( 'by_project_id' ) 56 | ->with( $this->equalTo(2) ) 57 | ->will( $this->returnValue($stubbed_originals) ); 58 | $translations = $this->android->read_translations_from_file( 'data/translation.android.xml', (object)array( 'id' => 2 ) ); 59 | foreach( $this->entries as $sample ) { 60 | list( $context, $original, $translation ) = $sample; 61 | $this->assertEquals( $translation, $translations->translate( $original, $context ) ); 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /t/tests/test_warnings.php: -------------------------------------------------------------------------------- 1 | is_baba = create_function('$o, $t, $l', 'return $t == "баба"? true : "error";'); 7 | $this->is_equal = create_function('$o, $t, $l', 'return $t == $o? true : "error";'); 8 | $this->w = new GP_Translation_Warnings; 9 | $this->with_equal = new GP_Translation_Warnings; 10 | $this->with_equal->add( 'is_equal', $this->is_equal ); 11 | $this->standard_plural_locale = $this->factory->locale->create(); 12 | } 13 | 14 | function test_add() { 15 | $this->w->add( 'is_baba', $this->is_baba ); 16 | $this->assertEquals( true, $this->w->has( 'is_baba' ) ); 17 | $this->assertEquals( false, $this->w->has( 'is_dyado' ) ); 18 | } 19 | 20 | function test_remove() { 21 | $this->w->add( 'is_baba', $this->is_baba ); 22 | $this->assertEquals( true, $this->w->has( 'is_baba' ) ); 23 | $this->w->remove( 'is_baba' ); 24 | $this->assertEquals( false, $this->w->has( 'is_baba' ) ); 25 | } 26 | 27 | function test_check() { 28 | $this->w->add( 'is_baba', $this->is_baba ); 29 | $this->assertEquals( array( 30 | 1 => array('is_baba' => 'error')), 31 | $this->w->check( 'baba', null, array('баба', 'баби'), $this->standard_plural_locale ) ); 32 | $this->assertEquals( null, 33 | $this->w->check( 'baba', null, array('баба', 'баба', 'баба'), $this->standard_plural_locale ) ); 34 | } 35 | 36 | /** 37 | * For the plural form, corresponding to the number 1 check only against the singular, not also against the plural 38 | */ 39 | function test_check_singular_plural_correspondence() { 40 | $this->assertEquals( null, 41 | $this->with_equal->check( 'baba', 'babas', array('baba', 'babas'), $this->standard_plural_locale ) ); 42 | $this->assertEquals( array(1 => array('is_equal' => 'error')), 43 | $this->with_equal->check( 'baba', 'babas', array('baba', 'baba'), $this->standard_plural_locale ) ); 44 | $this->assertEquals( array(0 => array('is_equal' => 'error')), 45 | $this->with_equal->check( 'baba', 'babas', array('babas', 'babas'), $this->standard_plural_locale ) ); 46 | } 47 | 48 | /** 49 | * If a locale has no plural forms, we should check only against the plural original, since 50 | * it probably contains the placeholders 51 | */ 52 | function test_check_no_plural_forms_locales() { 53 | $no_plural_locale = new GP_Locale; 54 | $no_plural_locale->nplurals = 1; 55 | $no_plural_locale->plural_expression = '0'; 56 | $this->assertEquals( null, 57 | $this->with_equal->check( 'baba', 'babas', array('babas'), $no_plural_locale ) ); 58 | $this->assertEquals( array(0 => array('is_equal' => 'error')), 59 | $this->with_equal->check( 'baba', 'babas', array('baba'), $no_plural_locale ) ); 60 | $this->assertEquals( array(0 => array('is_equal' => 'error')), 61 | $this->with_equal->check( 'baba', 'babas', array('xxx'), $no_plural_locale ) ); 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /install.php: -------------------------------------------------------------------------------- 1 | ' . __('Log in') . ''; 63 | 64 | if ( ! $errors ) { 65 | gp_create_initial_contents( $user_name, $admin_password, $admin_email ); 66 | } 67 | 68 | $show_htaccess_instructions = ! gp_set_htaccess() && empty( $errors ); 69 | $action = 'installed'; 70 | } else { 71 | $action = 'install'; 72 | } 73 | } 74 | else { 75 | $action = 'install'; 76 | $user_name = $admin_email = ''; 77 | } 78 | 79 | gp_tmpl_load( 'install', get_defined_vars() ); -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | HOW TO FIND YOUR WAY AROUND THE GLOTPRESS CODEBASE? 2 | 3 | Say you want to fix a bug, add a feature, or understand how something in GlotPress works. You came to the right place. 4 | 5 | First, GlotPress shares a lot with WordPress, bbPress and actually uses BackPress. Familiarity with these systems will be helpful. 6 | 7 | The structure of the project is very MVC-like. Models are called Things, Views are Templates and Controllers are Routes. 8 | 9 | *** Routes *** 10 | 11 | Each route is responsible for some URL pattern. For example the method single() of the class GP_Route_Project is responsible for 12 | URLs like /project/{project-slug}. 13 | 14 | The active route is chosen by the router in gp-includes/router.php. It's a simple loop over some regular expressions. The first match wins. 15 | 16 | Each route class handles a logical group of requests. For example, the project route is responsible for CRUD for projects. 17 | 18 | A route retrieves some data via the Things, does some magic (aka logic) based on the request parameters and the data and in the end either 19 | renders a template or redirects. 20 | 21 | All the routes live in gp-includes/routes/*.php 22 | 23 | *** Things *** 24 | 25 | Things is a poor men's ORM. Sometimes it's just better to be poor. It keeps you closer to the ground. 26 | 27 | The main goal of a Thing is *not* to hide SQL behind a OOP wall. It's goal is to help you better structure your code. It gives you a place to put all 28 | the functions related to an entity in your system. 29 | 30 | For example, let's take the GP_Project class, which is a descendant of GP_Thing. It has methods like `by_path()`, which finds a project by its path, 31 | `sub_projects()`, which retrieves all sub-projects of a project and so on. 32 | 33 | Some very commonly used functionality like find by id, create, very simple searches, deleting/updating come for free from the parent GP_Thing class. 34 | 35 | If you need more performance (less memory footprint), you have a very easy way to opt out of mapping the results of the queries 36 | to a Thing class. Just append _no_map() to the method name. 37 | 38 | Things provide basic validation tools, which come very handy when going through the endless CRUD forms. 39 | 40 | Since static variables cause all sort of pains in PHP, you can access an instance of each Thing like GP::$project. 41 | 42 | All Things live in gp-includes/things/*.php 43 | 44 | *** Templates *** 45 | 46 | These are just plain PHP files. Some variables come from above. And we can load other templates. 47 | 48 | All templates live in gp-templates/*.php 49 | 50 | *** Testing *** 51 | 52 | All tests live in t/. Go in t/ and run: 53 | 54 | $ phpunit all 55 | 56 | You will need to install phpunit: http://www.phpunit.de/manual/current/en/installation.html 57 | 58 | 59 | *** TODO *** 60 | - routes: notices & errors 61 | - route: die 62 | - route: capabilities checks 63 | - route: headers for download, stuff like that 64 | - templates: helpers 65 | - templates: links function 66 | - tests 67 | - init phase 68 | - plugins: where to put 69 | - plugins: GP_Plugin base class 70 | - API calls -------------------------------------------------------------------------------- /t/tests/test_format_resx.php: -------------------------------------------------------------------------------- 1 | resx = new GP_Format_ResX; 7 | $this->entries = array( 8 | array('normal_string', 'Normal String', 'Just A Normal String', ''), 9 | array('with_a_quote', 'I\'m with a quote', 'I\'m with a quote', ''), 10 | array('with_newlines', "new\nlines", "I\nhave\nnew\nlines", ''), 11 | array('with_doublequotes', 'double "quotes"', 'I have double "quotes"', ''), 12 | array('with_utf8', 'питка', 'баба ми омеси питка', ''), 13 | array('with_lt', 'you < me', 'ти < аз', ''), 14 | array('with_gt', 'me > you', "аз > ти", ''), 15 | array('with_amps', 'me & you are not &', 'аз & ти не сме &', ''), 16 | array('with_comment', 'baba', 'баба', 'Me, myself & Irene'), 17 | ); 18 | } 19 | 20 | function test_export() { 21 | $entries_for_export = array(); 22 | foreach( $this->entries as $sample ) { 23 | list( $context, $original, $translation, $comment ) = $sample; 24 | $entries_for_export[] = (object)array( 25 | 'context' => $context, 26 | 'singular' => $original, 27 | 'translations' => array($translation), 28 | 'extracted_comments' => $comment, 29 | ); 30 | } 31 | $this->assertEquals( file_get_contents( 'data/translation.resx.xml' ), $this->resx->print_exported_file( 'p', 'l', 't', $entries_for_export ) ); 32 | } 33 | 34 | 35 | function test_read_originals() { 36 | $translations = $this->resx->read_originals_from_file( 'data/originals.resx.xml' ); 37 | $this->assertEquals( count($this->entries ), count( $translations->entries ), 'number of read originals is different from the expected' ); 38 | foreach( $this->entries as $sample ) { 39 | list( $context, $original, $translation, $comment ) = $sample; 40 | $translatable_entry = new Translation_Entry( array('singular' => $original, 'context' => $context, 'extracted_comments' => $comment ) ); 41 | $entry = $translations->translate_entry( $translatable_entry ); 42 | $this->assertEquals( $original, $entry->singular ); 43 | $this->assertEquals( $context, $entry->context ); 44 | $this->assertEquals( $comment, $entry->extracted_comments ); 45 | } 46 | } 47 | 48 | function test_read_translations() { 49 | $stubbed_originals = array(); 50 | foreach( $this->entries as $sample ) { 51 | list( $context, $original, $translation ) = $sample; 52 | $stubbed_originals[] = new GP_Original( array( 'singular' => $original, 'context' => $context ) ); 53 | } 54 | GP::$original = $this->getMock( 'GP_Original', array('by_project_id') ); 55 | GP::$original->expects( $this->once() ) 56 | ->method( 'by_project_id' ) 57 | ->with( $this->equalTo(2) ) 58 | ->will( $this->returnValue($stubbed_originals) ); 59 | $translations = $this->resx->read_translations_from_file( 'data/translation.resx.xml', (object)array( 'id' => 2 ) ); 60 | foreach( $this->entries as $sample ) { 61 | list( $context, $original, $translation ) = $sample; 62 | $this->assertEquals( $translation, $translations->translate( $original, $context ) ); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /pomo/entry.php: -------------------------------------------------------------------------------- 1 | $value) { 50 | $this->$varname = $value; 51 | } 52 | if (isset($args['plural']) && $args['plural']) $this->is_plural = true; 53 | if (!is_array($this->translations)) $this->translations = array(); 54 | if (!is_array($this->references)) $this->references = array(); 55 | if (!is_array($this->flags)) $this->flags = array(); 56 | } 57 | 58 | /** 59 | * PHP4 constructor. 60 | */ 61 | public function Translation_Entry( $args = array() ) { 62 | self::__construct( $args ); 63 | } 64 | 65 | /** 66 | * Generates a unique key for this entry 67 | * 68 | * @return string|bool the key or false if the entry is empty 69 | */ 70 | function key() { 71 | if ( null === $this->singular || '' === $this->singular ) return false; 72 | 73 | // Prepend context and EOT, like in MO files 74 | $key = !$this->context? $this->singular : $this->context.chr(4).$this->singular; 75 | // Standardize on \n line endings 76 | $key = str_replace( array( "\r\n", "\r" ), "\n", $key ); 77 | 78 | return $key; 79 | } 80 | 81 | /** 82 | * @param object $other 83 | */ 84 | function merge_with(&$other) { 85 | $this->flags = array_unique( array_merge( $this->flags, $other->flags ) ); 86 | $this->references = array_unique( array_merge( $this->references, $other->references ) ); 87 | if ( $this->extracted_comments != $other->extracted_comments ) { 88 | $this->extracted_comments .= $other->extracted_comments; 89 | } 90 | 91 | } 92 | } 93 | endif; -------------------------------------------------------------------------------- /t/tests/test_format_strings.php: -------------------------------------------------------------------------------- 1 | strings = new GP_Format_Strings; 8 | $this->entries = array( 9 | array('Normal String', 'Normal String', 'Just A Normal String', ''), 10 | array('I\'m with a quote', 'I\'m with a quote', 'I\'m with a quote', ''), 11 | array('double "quotes"', 'double "quotes"', 'I have double "quotes"', ''), 12 | array('питка', 'питка', 'баба ми омеси питка', ''), 13 | array('you < me', 'you < me', 'ти < аз', ''), 14 | array('me > you', 'me > you', "аз > ти", ''), 15 | array('me & you are not &', 'me & you are not &', 'аз & ти не сме &', ''), 16 | array('baba', 'baba', 'баба', 'Me, myself & Irene'), 17 | ); 18 | } 19 | 20 | function test_export() { 21 | $entries_for_export = array(); 22 | 23 | foreach( $this->entries as $sample ) { 24 | list( $context, $original, $translation, $comment ) = $sample; 25 | 26 | $entries_for_export[] = (object)array( 27 | 'context' => $context, 28 | 'singular' => $original, 29 | 'translations' => array($translation), 30 | 'extracted_comments' => $comment, 31 | ); 32 | } 33 | 34 | $file = file_get_contents( 'data/translation.strings' ); 35 | $exported = $this->strings->print_exported_file( 'p', 'l', 't', $entries_for_export ); 36 | 37 | $file = mb_convert_encoding( $file, 'UTF-8', 'UTF-16LE' ); 38 | $exported = mb_convert_encoding( $exported, 'UTF-8', 'UTF-16' ); 39 | 40 | $this->assertEquals( $file, $exported ); 41 | } 42 | 43 | function test_read_originals() { 44 | $translations = $this->strings->read_originals_from_file( 'data/originals.utf16le.strings' ); 45 | $this->assertEquals( count( $this->entries ), count( $translations->entries ), 'number of read originals is different from the expected' ); 46 | 47 | foreach( $this->entries as $sample ) { 48 | list( $context, $original, $translation, $comment ) = $sample; 49 | $translatable_entry = new Translation_Entry( array('singular' => $original, 'context' => $context, 'extracted_comments' => $comment ) ); 50 | $entry = $translations->translate_entry( $translatable_entry ); 51 | $this->assertEquals( $original, $entry->singular ); 52 | $this->assertEquals( $context, $entry->context ); 53 | $this->assertEquals( $comment, $entry->extracted_comments ); 54 | } 55 | } 56 | 57 | function test_read_translations() { 58 | $stubbed_originals = array(); 59 | 60 | foreach( $this->entries as $sample ) { 61 | list( $context, $original, $translation ) = $sample; 62 | $stubbed_originals[] = new GP_Original( array( 'singular' => $original, 'context' => $context ) ); 63 | } 64 | 65 | GP::$original = $this->getMock( 'GP_Original', array('by_project_id') ); 66 | GP::$original->expects( $this->once() ) 67 | ->method( 'by_project_id' ) 68 | ->with( $this->equalTo(2) ) 69 | ->will( $this->returnValue($stubbed_originals) ); 70 | 71 | $translations = $this->strings->read_translations_from_file( 'data/translation.strings', (object)array( 'id' => 2 ) ); 72 | 73 | foreach( $this->entries as $sample ) { 74 | list( $context, $original, $translation ) = $sample; 75 | $this->assertEquals( $translation, $translations->translate( $original, $context ) ); 76 | } 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /gp-includes/backpress/class.wp-http-ixr-client.php: -------------------------------------------------------------------------------- 1 | scheme = $bits['scheme']; 17 | $this->server = $bits['host']; 18 | $this->port = isset($bits['port']) ? $bits['port'] : 80; 19 | $this->path = isset($bits['path']) ? $bits['path'] : '/'; 20 | 21 | // Make absolutely sure we have a path 22 | if (!$this->path) { 23 | $this->path = '/'; 24 | } 25 | } else { 26 | $this->scheme = 'http'; 27 | $this->server = $server; 28 | $this->path = $path; 29 | $this->port = $port; 30 | } 31 | $this->useragent = 'The Incutio XML-RPC PHP Library'; 32 | $this->timeout = $timeout; 33 | } 34 | 35 | function query() 36 | { 37 | $args = func_get_args(); 38 | $method = array_shift($args); 39 | $request = new IXR_Request($method, $args); 40 | $xml = $request->getXml(); 41 | 42 | $url = $this->scheme . '://' . $this->server . ':' . $this->port . $this->path; 43 | $args = array( 44 | 'headers' => array('Content-Type' => 'text/xml'), 45 | 'user-agent' => $this->useragent, 46 | 'body' => $xml, 47 | ); 48 | 49 | // Merge Custom headers ala #8145 50 | foreach ( $this->headers as $header => $value ) 51 | $args['headers'][$header] = $value; 52 | 53 | if ( $this->timeout !== false ) 54 | $args['timeout'] = $this->timeout; 55 | 56 | // Now send the request 57 | if ($this->debug) { 58 | echo '
'.htmlspecialchars($xml)."\n
\n\n"; 59 | } 60 | 61 | $response = wp_remote_post($url, $args); 62 | 63 | if ( is_wp_error($response) ) { 64 | $errno = $response->get_error_code(); 65 | $errorstr = $response->get_error_message(); 66 | $this->error = new IXR_Error(-32300, "transport error: $errno $errstr"); 67 | return false; 68 | } 69 | 70 | $code = $response['response']['code']; 71 | if ( $code != 200 ) { 72 | $this->error = new IXR_Error(-32301, "transport error - HTTP status code was not 200 ($code)"); return false; 73 | } 74 | 75 | if ($this->debug) { 76 | echo '
'.htmlspecialchars($response['body'])."\n
\n\n"; 77 | } 78 | 79 | // Now parse what we've got back 80 | $this->message = new IXR_Message( $response['body'] ); 81 | if (!$this->message->parse()) { 82 | // XML error 83 | $this->error = new IXR_Error(-32700, 'parse error. not well formed'); 84 | return false; 85 | } 86 | 87 | // Is the message a fault? 88 | if ($this->message->messageType == 'fault') { 89 | $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString); 90 | return false; 91 | } 92 | 93 | // Message must be OK 94 | return true; 95 | } 96 | } 97 | ?> -------------------------------------------------------------------------------- /js/translations-page.js: -------------------------------------------------------------------------------- 1 | jQuery(function($) { 2 | $gp.showhide('#upper-filters-toolbar a.sort', '#upper-filters-toolbar dl.sort', { 3 | show_text: $gp_translations_options.sort + ' ↓', 4 | hide_text: $gp_translations_options.sort + ' ↑', 5 | focus: '#sort\\[by\\]' 6 | }); 7 | $gp.showhide('#upper-filters-toolbar a.filter', '#upper-filters-toolbar dl.filters', { 8 | show_text: $gp_translations_options.filter + ' ↓', 9 | hide_text: $gp_translations_options.filter + ' ↑', 10 | focus: '#filters\\[term\\]' 11 | }); 12 | 13 | var rows_checked = 0; 14 | 15 | $('#bulk-priority').hide(); 16 | $('#bulk-action').on( 'change', function (e) { 17 | var optionSelected = $("option:selected", this); 18 | if ( 'set-priority' == optionSelected.val() ) { 19 | $('#bulk-priority').show(); 20 | } else { 21 | $('#bulk-priority').hide(); 22 | } 23 | }); 24 | $('form.filters-toolbar.bulk-actions').submit(function(e) { 25 | var row_ids = $('input:checked', $('table#translations th.checkbox')).map(function() { 26 | return $(this).parents('tr.preview').attr('row'); 27 | }).get().join(','); 28 | $('input[name="bulk[row-ids]"]', $(this)).val(row_ids); 29 | }); 30 | 31 | $('a#export').click(function() { 32 | var format = $('#export-format').val(); 33 | var what_to_export = $('#what-to-export').val(); 34 | var url = ''; 35 | if (what_to_export == 'filtered') { 36 | var separator = ( $(this).attr('filters').indexOf('?') == -1 )? '?' : '&'; 37 | url = $(this).attr('filters') + separator + 'format='+format; 38 | } else { 39 | url = $(this).attr('href') + '?format='+format; 40 | } 41 | window.location = url; 42 | return false; 43 | }); 44 | 45 | var lastClicked = false; 46 | // Check all checkboxes from WP common.js, synced with [20400] 47 | $('tbody').children().children('.checkbox').find(':checkbox').click( function(e) { 48 | if ( 'undefined' == e.shiftKey ) { return true; } 49 | if ( e.shiftKey ) { 50 | if ( !lastClicked ) { return true; } 51 | checks = $( lastClicked ).closest( 'table' ).find( ':checkbox' ); 52 | first = checks.index( lastClicked ); 53 | last = checks.index( this ); 54 | checked = $(this).prop('checked'); 55 | if ( 0 < first && 0 < last && first != last ) { 56 | checks.slice( first, last ).prop( 'checked', function(){ 57 | if ( $(this).closest('tr').is(':visible') ) 58 | return checked; 59 | 60 | return false; 61 | }); 62 | } 63 | } 64 | lastClicked = this; 65 | return true; 66 | }); 67 | 68 | $('thead, tfoot').find('.checkbox :checkbox').click( function(e) { 69 | var c = $(this).prop('checked'), 70 | kbtoggle = 'undefined' == typeof toggleWithKeyboard ? false : toggleWithKeyboard, 71 | toggle = e.shiftKey || kbtoggle; 72 | 73 | $(this).closest( 'table' ).children( 'tbody' ).filter(':visible') 74 | .children().children('.checkbox').find(':checkbox') 75 | .prop('checked', function() { 76 | if ( $(this).closest('tr').is(':hidden') ) 77 | return false; 78 | if ( toggle ) 79 | return $(this).prop( 'checked' ); 80 | else if (c) 81 | return true; 82 | return false; 83 | }); 84 | 85 | $(this).closest('table').children('thead, tfoot').filter(':visible') 86 | .children().children('.checkbox').find(':checkbox') 87 | .prop('checked', function() { 88 | if ( toggle ) 89 | return false; 90 | else if (c) 91 | return true; 92 | return false; 93 | }); 94 | }); 95 | 96 | }); 97 | -------------------------------------------------------------------------------- /gp-includes/install-upgrade.php: -------------------------------------------------------------------------------- 1 | 70 | RewriteEngine On 71 | RewriteBase ' . $path . ' 72 | RewriteCond %{REQUEST_FILENAME} !-f 73 | RewriteCond %{REQUEST_FILENAME} !-d 74 | RewriteRule . ' . $path . 'index.php [L] 75 | 76 | # END GlotPress'; 77 | } 78 | 79 | 80 | 81 | function gp_upgrade_data( $db_version ) { 82 | global $gpdb; 83 | if ( $db_version < 190 ) { 84 | $gpdb->query("UPDATE $gpdb->translations SET status = REPLACE(REPLACE(status, '-', ''), '+', '');"); 85 | } 86 | } 87 | 88 | function gp_install() { 89 | global $gpdb; 90 | 91 | $errors = gp_upgrade_db(); 92 | 93 | if ( $errors ) return $errors; 94 | 95 | gp_update_option( 'uri', guess_uri() ); 96 | } 97 | 98 | function gp_create_initial_contents( $user_name = null, $admin_password = null, $admin_email = null ) { 99 | global $gpdb; 100 | 101 | $gpdb->insert( $gpdb->projects, array( 'name' => __('Sample'), 'slug' => __('sample'), 'description' => __('A Sample Project'), 'path' => __('sample') ) ); 102 | $gpdb->insert( $gpdb->originals, array( 'project_id' => 1, 'singular' => __('GlotPress FTW'), 'comment' => __('FTW means For The Win'), 'context' => 'dashboard', 'references' => 'bigfile:666 little-dir/small-file.php:71' ) ); 103 | $gpdb->insert( $gpdb->originals, array( 'project_id' => 1, 'singular' => __('A GlotPress'), 'plural' => __('Many GlotPresses') ) ); 104 | 105 | $gpdb->insert( $gpdb->translation_sets, array( 'name' => __('My Translation'), 'slug' => __('my'), 'project_id' => 1, 'locale' => 'bg', ) ); 106 | 107 | if ( isset( $user_name, $admin_password, $admin_email ) ) { 108 | $admin = GP::$user->create( array( 'user_login' => $user_name, 'user_pass' => $admin_password, 'user_email' => $admin_email ) ); 109 | GP::$permission->create( array( 'user_id' => $admin->id, 'action' => 'admin' ) ); 110 | } 111 | } -------------------------------------------------------------------------------- /gp-templates/project-permissions.php: -------------------------------------------------------------------------------- 1 | name ) ); 3 | gp_breadcrumb_project( $project ); 4 | gp_tmpl_header(); 5 | ?> 6 |

7 |

8 | 9 | 10 ): ?> 10 | Add → 11 | 12 |

13 | 14 | 15 |

16 | 17 |
    18 | 19 |
  • 20 | 21 | %s', gp_url_profile( $permission->user->user_nicename ), esc_html( $permission->user->user_login ) ); ?> 22 | action ) ); ?> 23 | locale_slug ); ?> 24 | 25 | set_slug ); ?> 26 | 27 |
  • 28 | 29 |
30 | 31 | 32 |

33 |
    34 | 35 |
  • 36 | 37 | %s', gp_url_profile( $permission->user->user_nicename ), esc_html( $permission->user->user_login ) ); ?> 38 | action )); ?> 39 | locale_slug ); ?> 40 | 41 | set_slug ); ?> 42 | 43 | project, esc_html( $permission->project->name ) ); ?> 44 |
  • 45 | 46 |
47 | 48 | 49 | 50 | 51 |
52 |

53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 |
62 | 63 | 64 |
65 | 66 | _object_type = 'plugin_'.$this->id; 18 | } 19 | 20 | 21 | /** 22 | * Retrieve an option, specific to your plugin. 23 | * 24 | * You don't have to prefix the key or to tie its name to your plugin. 25 | * 26 | * @param string $key 27 | * @return mixed the value of the option, or null if it wasn't found 28 | */ 29 | function get_option( $key ) { 30 | global $gpdb; 31 | // TODO: add caching (see gp_get_option_from_db()) 32 | $row = $gpdb->get_row( $gpdb->prepare( "SELECT `meta_value` FROM `$gpdb->meta` WHERE `object_type` = %s AND `meta_key` = %s", $this->_object_type, $key ) ); 33 | if ( is_object( $row ) ) { 34 | $r = maybe_unserialize( $row->meta_value ); 35 | } else { 36 | $r = null; 37 | } 38 | return $r; 39 | } 40 | 41 | /** 42 | * Update an option, specific to your plugin. 43 | * 44 | * You don't have to prefix the key or to tie its name to your plugin. 45 | * 46 | * @param string $key 47 | * @param mixed $value Can be anything serializable 48 | * @return bool 49 | */ 50 | function update_option( $key, $value ) { 51 | return gp_update_meta( 0, $key, $value, $this->_object_type, true ); 52 | } 53 | 54 | /** 55 | * Adds a method in this class as an action with the same name. 56 | * 57 | * For example $this->add_action( 'init', ... ) will add $this->init() as an init action 58 | * 59 | * @param string $action_name The name of the action and the method. 60 | * @param array $args Two keys are supported: 61 | * - priority => priority of the action. Positive integer. Lower priority means earlier execution. Default is 10. 62 | * - args => how many arguments the action accepts. Default is 1. 63 | * 64 | * @see add_action() 65 | */ 66 | function add_action( $action_name, $args = array() ) { 67 | return $this->add_filter( $action_name, $args ); 68 | } 69 | 70 | /** 71 | * Adds a method in this class as a filter with the same name. 72 | * 73 | * For example $this->add_filter( 'the_content', ... ) will add $this->the_content() as a the_content filter 74 | * 75 | * @param string $filter_name The name of the filter and the method. 76 | * @param array $args Two keys are supported: 77 | * - priority => priority of the filter. Positive integer. Lower priority means earlier execution. Default is 10. 78 | * - args => how many arguments the filter accepts. Default is 1. 79 | * 80 | * @see add_action() 81 | */ 82 | function add_filter( $filter_name, $args = array() ) { 83 | return $this->_call_wp_plugin_api_function( 'add_filter', $filter_name, $args ); 84 | } 85 | 86 | function _call_wp_plugin_api_function( $wp_function, $tag, $args = array() ) { 87 | $args['tag'] = $tag; 88 | $defaults = array( 'priority' => 10, 'args' => 1 ); 89 | $args = array_merge( $defaults, $args ); 90 | return $wp_function( $args['tag'], array( &$this, $args['tag'] ), $args['priority'], $args['args'] ); 91 | } 92 | 93 | function remove_action( $action_name, $args = array() ) { 94 | return $this->remove_filter( $action_name, $args ); 95 | } 96 | 97 | function remove_filter( $filter_name, $args = array() ) { 98 | return $this->_call_wp_plugin_api_function( 'remove_filter', $filter_name, $args ); 99 | } 100 | } -------------------------------------------------------------------------------- /gp-includes/routes/translation-set.php: -------------------------------------------------------------------------------- 1 | project_id = gp_get( 'project_id' ); 6 | $project = $set->project_id? GP::$project->get( $set->project_id ) : null; 7 | if ( $this->cannot_edit_set_and_redirect( $set ) ) return; 8 | $this->tmpl( 'translation-set-new', get_defined_vars() ); 9 | } 10 | 11 | function new_post() { 12 | $new_set = new GP_Translation_Set( gp_post( 'set', array() ) ); 13 | if ( $this->cannot_edit_set_and_redirect( $new_set ) ) return; 14 | if ( $this->invalid_and_redirect( $new_set ) ) return; 15 | $created_set = GP::$translation_set->create_and_select( $new_set ); 16 | if ( $created_set ) $project = GP::$project->get( $created_set->project_id ); 17 | if ( !$created_set ) { 18 | $this->errors[] = __('Error in creating translation set!'); 19 | $this->redirect( gp_url( '/sets/-new', array( 'project_id' => $new_set->project_id ) ) ); 20 | } else { 21 | $this->notices[] = __('The translation set was created!'); 22 | $this->redirect( gp_url_project_locale( GP::$project->get( $created_set->project_id ), $created_set->locale, $created_set->slug ) ); 23 | } 24 | } 25 | 26 | function single( $set_id ) { 27 | $items = $this->get_set_project_and_locale_from_set_id_or_404( $set_id ); 28 | if ( !$items) return; 29 | list( $set, $project, $locale ) = $items; 30 | $this->redirect( gp_url_project( $project, array( $set->locale, $set->slug ) ) ); 31 | } 32 | 33 | function edit_get( $set_id ) { 34 | $items = $this->get_set_project_and_locale_from_set_id_or_404( $set_id ); 35 | if ( !$items ) return; 36 | list( $set, $project, $locale ) = $items; 37 | if ( $this->cannot_and_redirect( 'write', 'project', $set->project_id, gp_url_project( $project ) ) ) return; 38 | $url = gp_url_project( $project, gp_url_join( $set->locale, $set->slug ) ); 39 | $this->tmpl( 'translation-set-edit', get_defined_vars() ); 40 | } 41 | 42 | function edit_post( $set_id ) { 43 | $items = $this->get_set_project_and_locale_from_set_id_or_404( $set_id ); 44 | if ( !$items ) return; 45 | list( $set, $project, $locale ) = $items; 46 | $new_set = new GP_Translation_Set( gp_post( 'set', array() ) ); 47 | if ( $this->cannot_edit_set_and_redirect( $new_set ) ) return; 48 | if ( $this->invalid_and_redirect( $new_set, gp_url( '/sets/-new' ) ) ) return; 49 | if ( !$set->update( $new_set ) ) { 50 | $this->errors[] = __('Error in updating translation set!'); 51 | $this->redirect(); 52 | return; 53 | } 54 | $project = GP::$project->get( $new_set->project_id ); 55 | $this->notices[] = __( 'The translation set was updated!' ); 56 | $this->redirect( gp_url_project_locale( $project, $new_set->locale, $new_set->slug ) ); 57 | } 58 | 59 | private function cannot_edit_set_and_redirect( $set ) { 60 | return $this->cannot_and_redirect( 'write', 'project', $set->project_id ); 61 | } 62 | 63 | private function get_set_project_and_locale_from_set_id_or_404( $set_id ) { 64 | $set = GP::$translation_set->get( $set_id ); 65 | if ( !$set ) { 66 | $this->die_with_404( array( 'title' => "Translation set wasn't found" ) ); 67 | return; 68 | } 69 | $project = GP::$project->get( $set->project_id ); 70 | if ( !$project ) { 71 | $this->die_with_404( array( 'title' => "The project associated with this translation set wasn't found" ) ); 72 | return; 73 | } 74 | $locale = $locale = GP_Locales::by_slug( $set->locale ); 75 | if ( !$locale ) { 76 | $this->die_with_404( array( 'title' => "The locale associated with this translation set wasn't found" ) ); 77 | return; 78 | } 79 | return array( $set, $project, $locale ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /gp-templates/glossary-entry-row.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | term ); ?> 4 | part_of_speech ); ?> 5 | translation ); ?> 6 | comment ) ) ); ?> 7 | 8 | 9 | 10 |
    11 |
  • 12 |
13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |
22 |
23 |
31 |
32 |
33 |
34 |
35 |
36 |

37 | 38 | 39 | 40 |

41 |
42 | 43 |
44 |

45 |
46 |
47 |
date_modified; ?>
48 |
49 | user_login ): ?> 50 |
51 |
52 |
user_display_name && $entry->user_display_name != $entry->user_login ) { 54 | printf( '%s (%s)', $entry->user_display_name, $entry->user_login ); 55 | } else { 56 | echo $entry->user_login; 57 | } 58 | ?>
59 |
60 |
61 |
62 |
63 | 64 |
65 |
66 | 67 |
68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /gp-includes/backpress/interface.bp-options.php: -------------------------------------------------------------------------------- 1 | translate($text), $text, $domain); 30 | } 31 | 32 | function translate_with_gettext_context( $text, $context, $domain = 'default' ) { 33 | $translations = get_translations_for_domain( $domain ); 34 | return apply_filters( 'gettext_with_context', $translations->translate( $text, $context ), $text, $context, $domain); 35 | } 36 | 37 | function __( $text, $domain = 'default' ) { 38 | return translate( $text, $domain ); 39 | } 40 | 41 | function esc_attr__( $text, $domain = 'default' ) { 42 | return esc_attr( translate( $text, $domain ) ); 43 | } 44 | 45 | function esc_html__( $text, $domain = 'default' ) { 46 | return esc_html( translate( $text, $domain ) ); 47 | } 48 | 49 | function _e( $text, $domain = 'default' ) { 50 | echo translate( $text, $domain ); 51 | } 52 | 53 | function esc_attr_e( $text, $domain = 'default' ) { 54 | echo esc_attr( translate( $text, $domain ) ); 55 | } 56 | 57 | function esc_html_e( $text, $domain = 'default' ) { 58 | echo esc_html( translate( $text, $domain ) ); 59 | } 60 | 61 | function _x( $single, $context, $domain = 'default' ) { 62 | return translate_with_gettext_context( $single, $context, $domain ); 63 | } 64 | 65 | function esc_attr_x( $single, $context, $domain = 'default' ) { 66 | return esc_attr( translate_with_gettext_context( $single, $context, $domain ) ); 67 | } 68 | 69 | function esc_html_x( $single, $context, $domain = 'default' ) { 70 | return esc_html( translate_with_gettext_context( $single, $context, $domain ) ); 71 | } 72 | 73 | function _n($single, $plural, $number, $domain = 'default') { 74 | $translations = get_translations_for_domain( $domain ); 75 | $translation = $translations->translate_plural( $single, $plural, $number ); 76 | return apply_filters( 'ngettext', $translation, $single, $plural, $number ); 77 | } 78 | 79 | function _nx($single, $plural, $number, $context, $domain = 'default') { 80 | $translations = get_translations_for_domain( $domain ); 81 | $translation = $translations->translate_plural( $single, $plural, $number, $context ); 82 | return apply_filters( 'ngettext_with_context ', $translation, $single, $plural, $number, $context ); 83 | } 84 | 85 | function _n_noop( $single, $plural, $number = 1, $domain = 'default' ) { 86 | return array( $single, $plural ); 87 | } 88 | 89 | function load_textdomain( $domain, $mofile ) { 90 | global $l10n; 91 | 92 | if ( !is_readable( $mofile ) ) return; 93 | 94 | $mo = new MO(); 95 | $mo->import_from_file( $mofile ); 96 | 97 | if ( isset( $l10n [$domain] ) ) 98 | $mo->merge_with( $l10n[$domain] ); 99 | 100 | $l10n[$domain] = &$mo; 101 | } 102 | 103 | function load_default_textdomain() { 104 | $locale = get_locale(); 105 | 106 | $mofile = GP_LANG_PATH . "/$locale.mo"; 107 | 108 | load_textdomain('default', $mofile); 109 | } 110 | 111 | /** 112 | * Returns the Translations instance for a domain. If there isn't one, 113 | * returns empty Translations instance. 114 | * 115 | * @since 1.0.0 116 | * 117 | * @param string $domain 118 | * @return object A Translation instance 119 | */ 120 | function get_translations_for_domain( $domain ) { 121 | global $l10n; 122 | 123 | if( ! isset( $l10n[ $domain ] ) ) 124 | $l10n[ $domain ] = new Translations; 125 | 126 | return $l10n[ $domain ]; 127 | } -------------------------------------------------------------------------------- /gp-includes/template-links.php: -------------------------------------------------------------------------------- 1 | %4$s%5$s', $before, esc_attr( $url ), $attributes, $text, $after ); 15 | } 16 | 17 | function gp_link() { 18 | $args = func_get_args(); 19 | echo call_user_func_array('gp_link_get', $args); 20 | } 21 | 22 | function gp_link_with_ays_get( $url, $text, $attrs = array() ) { 23 | $ays_text = $attrs['ays-text']; 24 | unset( $attrs['ays-text'] ); 25 | $attrs['onclick'] = "return confirm('".esc_js( $ays_text )."');"; 26 | return gp_link_get( $url, $text, $attrs ); 27 | } 28 | 29 | function gp_link_with_ays() { 30 | $args = func_get_args(); 31 | echo call_user_func_array('gp_link_with_ays_get', $args); 32 | } 33 | 34 | function gp_link_project_get( $project_or_path, $text, $attrs = array() ) { 35 | $attrs = array_merge( array( 'title' => 'Project: '.$text ), $attrs ); 36 | return gp_link_get( gp_url_project( $project_or_path ), $text, $attrs ); 37 | } 38 | 39 | function gp_link_project() { 40 | $args = func_get_args(); 41 | echo call_user_func_array('gp_link_project_get', $args); 42 | } 43 | 44 | function gp_link_project_edit_get( $project, $text = null, $attrs = array() ) { 45 | if ( !GP::$user->current()->can( 'write', 'project', $project->id ) ) { 46 | return ''; 47 | } 48 | $text = $text? $text : __( 'Edit' ); 49 | return gp_link_get( gp_url_project( $project, '-edit' ), $text, gp_attrs_add_class( $attrs, 'action edit' ) ); 50 | } 51 | 52 | function gp_link_project_edit() { 53 | $args = func_get_args(); 54 | echo call_user_func_array('gp_link_project_edit_get', $args); 55 | } 56 | 57 | function gp_link_project_delete_get( $project, $text = false, $attrs = array() ) { 58 | if ( !GP::$user->current()->can( 'write', 'project', $project->id ) ) { 59 | return ''; 60 | } 61 | $text = $text? $text : __( 'Delete' ); 62 | return gp_link_get( gp_url_project( $project, '-delete' ), $text, gp_attrs_add_class( $attrs, 'action delete' ) ); 63 | } 64 | 65 | function gp_link_project_delete() { 66 | $args = func_get_args(); 67 | echo call_user_func_array('gp_link_project_delete_get', $args); 68 | } 69 | 70 | function gp_link_home_get() { 71 | return gp_link_get( gp_url( '/' ), __( 'Home' ), array( 'title' => __('Home Is Where The Heart Is') ) ); 72 | } 73 | 74 | function gp_link_home() { 75 | $args = func_get_args(); 76 | echo call_user_func_array('gp_link_home_get', $args); 77 | } 78 | 79 | function gp_link_login_get() { 80 | return gp_link_get( gp_url( '/login' ), __( 'Login' ), array( 'title' => __('Sign into GlotPress') ) ); 81 | } 82 | 83 | function gp_link_login() { 84 | $args = func_get_args(); 85 | echo call_user_func_array('gp_link_login_get', $args); 86 | } 87 | 88 | function gp_link_set_edit_get( $set, $project, $text = false, $attrs = array() ) { 89 | if ( !GP::$user->current()->can( 'write', 'project', $project->id ) ) { 90 | return ''; 91 | } 92 | $text = $text? $text : __( 'Edit' ); 93 | return gp_link_get( gp_url( gp_url_join( '/sets', $set->id, '-edit' ) ), $text, gp_attrs_add_class( $attrs, 'action edit' ) ); 94 | } 95 | 96 | function gp_link_set_edit() { 97 | $args = func_get_args(); 98 | echo call_user_func_array('gp_link_set_edit_get', $args); 99 | } 100 | 101 | function gp_link_glossary_edit_get( $glossary, $set, $text = false, $attrs = array() ) { 102 | if ( ! GP::$user->current()->can( 'approve', 'translation-set', $set->id ) ) { 103 | return ''; 104 | } 105 | 106 | $text = $text? $text : __( 'Edit' ); 107 | return gp_link_get( gp_url( gp_url_join( '/glossaries', $glossary->id, '-edit' ) ), $text, gp_attrs_add_class( $attrs, 'action edit' ) ); 108 | } 109 | 110 | function gp_link_glossary_edit() { 111 | $args = func_get_args(); 112 | echo call_user_func_array('gp_link_glossary_edit_get', $args); 113 | } 114 | -------------------------------------------------------------------------------- /gp-includes/backpress/functions.wp-scripts.php: -------------------------------------------------------------------------------- 1 | do_items( $handles ); 35 | } 36 | 37 | /** 38 | * Register new JavaScript file. 39 | * 40 | * @since r16 41 | * @param string $handle Script name 42 | * @param string $src Script url 43 | * @param array $deps (optional) Array of script names on which this script depends 44 | * @param string|bool $ver (optional) Script version (used for cache busting), set to NULL to disable 45 | * @param bool (optional) Wether to enqueue the script before or before 46 | * @return null 47 | */ 48 | function wp_register_script( $handle, $src, $deps = array(), $ver = false, $in_footer = false ) { 49 | global $wp_scripts; 50 | if ( !is_a($wp_scripts, 'WP_Scripts') ) 51 | $wp_scripts = new WP_Scripts(); 52 | 53 | $wp_scripts->add( $handle, $src, $deps, $ver ); 54 | if ( $in_footer ) 55 | $wp_scripts->add_data( $handle, 'group', 1 ); 56 | } 57 | 58 | /** 59 | * Localizes a script. 60 | * 61 | * Localizes only if script has already been added. 62 | * 63 | * @since r16 64 | * @see WP_Scripts::localize() 65 | */ 66 | function wp_localize_script( $handle, $object_name, $l10n ) { 67 | global $wp_scripts; 68 | if ( !is_a($wp_scripts, 'WP_Scripts') ) 69 | return false; 70 | 71 | return $wp_scripts->localize( $handle, $object_name, $l10n ); 72 | } 73 | 74 | /** 75 | * Remove a registered script. 76 | * 77 | * @since r16 78 | * @see WP_Scripts::remove() For parameter information. 79 | */ 80 | function wp_deregister_script( $handle ) { 81 | global $wp_scripts; 82 | if ( !is_a($wp_scripts, 'WP_Scripts') ) 83 | $wp_scripts = new WP_Scripts(); 84 | 85 | $wp_scripts->remove( $handle ); 86 | } 87 | 88 | /** 89 | * Enqueues script. 90 | * 91 | * Registers the script if src provided (does NOT overwrite) and enqueues. 92 | * 93 | * @since r16 94 | * @see wp_register_script() For parameter information. 95 | */ 96 | function wp_enqueue_script( $handle, $src = false, $deps = array(), $ver = false, $in_footer = false ) { 97 | global $wp_scripts; 98 | if ( !is_a($wp_scripts, 'WP_Scripts') ) 99 | $wp_scripts = new WP_Scripts(); 100 | 101 | if ( $src ) { 102 | $_handle = explode('?', $handle); 103 | $wp_scripts->add( $_handle[0], $src, $deps, $ver ); 104 | if ( $in_footer ) 105 | $wp_scripts->add_data( $_handle[0], 'group', 1 ); 106 | } 107 | $wp_scripts->enqueue( $handle ); 108 | } 109 | 110 | /** 111 | * Check whether script has been added to WordPress Scripts. 112 | * 113 | * The values for list defaults to 'queue', which is the same as enqueue for 114 | * scripts. 115 | * 116 | * @since WP unknown; BP unknown 117 | * 118 | * @param string $handle Handle used to add script. 119 | * @param string $list Optional, defaults to 'queue'. Others values are 'registered', 'queue', 'done', 'to_do' 120 | * @return bool 121 | */ 122 | function wp_script_is( $handle, $list = 'queue' ) { 123 | global $wp_scripts; 124 | if ( !is_a($wp_scripts, 'WP_Scripts') ) 125 | $wp_scripts = new WP_Scripts(); 126 | 127 | $query = $wp_scripts->query( $handle, $list ); 128 | 129 | if ( is_object( $query ) ) 130 | return true; 131 | 132 | return $query; 133 | } 134 | --------------------------------------------------------------------------------