Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement i18n/l10n solution for shared library files #7

Closed
bobbingwide opened this issue Jun 28, 2017 · 6 comments
Closed

Implement i18n/l10n solution for shared library files #7

bobbingwide opened this issue Jun 28, 2017 · 6 comments

Comments

@bobbingwide
Copy link
Owner

bobbingwide commented Jun 28, 2017

The shared library files are incorporated into multiple plugins. Some of them include translatable strings. We need to develop the most appropriate solution for ensuring that these strings are translated into the user's preferred language.

In the solution being developed for bobbingwide/oik/issues/9, rather than using the slightly more efficient solution originally developed in oik, we are changing the code to use the standard functions that support localization (l10n). The shared library files will need to be changed to use this same set of APIs. The replacement functions, that do not perform translation, are in class-BW-.php.
We then have to decide how to build and deliver .po and .mo files for each supported locale.

Proposal

  • Use a text domain of oik-libs
  • Ensure that any plugin that depends on shared library files that require translated strings loads the translation tables from languages/oik-libs-la_CY.mo
@bobbingwide
Copy link
Owner Author

The proposed solution will work fine for any plugin that's not delivered from WordPress.org.
But it's no good for plugins delivered from wordpress.org since WordPress doesn't deliver multiple .po and .mo files. It assumes each plugin will only use one text domain.

I wrote to UK WP Community

Hi, I'm trying to implement a shared library solution for some of my plugins on WordPress.org where the same PHP file is delivered by each plugin that needs it and that file may contain strings that need translating. Basically I want WordPress to ignore the text-domain parameter and find any available translation.

I think I need to look into solutions that will do just what I said in the last sentence.

@bobbingwide
Copy link
Owner Author

Having found I could happily use null as a text domain I wrote to core slack

I've been investigating methods for supporting a requirement to "Just Translate It" regardless of the text-domain and discovered that I can use a text domain of null. Does anyone else feel they need "Just Translate It" and would like to use null as the text domain?

Sergey Biryukov asked what's "Just Translate It"? My reply was.

Hi Sergey, I'm working on a solution that allows for shared library files between plugins / themes. I need to find a way to support translation of strings regardless of the place from which the file was loaded. So I don't really care what the text domain is, I just want the string translated.

My understanding is that the language file(s) from wordpress.org would contain the translation regardless of the domain I pass in the source code. I'd like it to find a translation if it can from the merged loaded domains.
I discovered that I could potentially implement this using null as the text domain and a filter hook for gettext checking the domain parameter.

Actually I wrote some tests to prove this was possible. Now I'm wondering what's the best approach for implementing the solution. My gut feel is to continue using null as the parameter.

@bobbingwide
Copy link
Owner Author

bobbingwide commented Jul 28, 2017

Using a null domain is a different approach. With this method there is no need to build language files for the oik-libs libraries. We just use what's delivered by the plugins. So, instead of changing oik_require_lib() to automatically load the oik-libs text domain, we leave it to the plugins and libs.

A library that requires translation will need to perform the following.

oik_require_lib( "oik-l10n" );
oik_l10n_enable_jit();

Then the next call to __( "translate me", null ); will lazy load the translations.

This solution does not cater for strings requiring context. e.g. "Check" - when used for banking.

@bobbingwide
Copy link
Owner Author

bobbingwide commented Aug 3, 2017

I have raised WordPress TRAC 41551 to Officially support use of null for text domain name parameter to l10n functions. See https://core.trac.wordpress.org/ticket/41551

The new unit tests only demonstrate that you can pass a value of null to:

  • load_textdomain()
  • unload_textdomain()
  • is_textdomain_loaded()
  • __()

I've also written tests for oik-libs ( in tests/test-translate-null-domain.php ) that demonstrated the proposed solution.

I then developed the solution in libs\oik-l10n.php with tests in tests\test-libs-oik-l10n.php.

Explanation of proposed solution

makepot finds the strings

  • makepot's job is to find strings that can be translated
  • WordPress.org expects each plugin and theme to use a unique domain
  • though it doesn't enforce it
  • So makepot outputs any translatable string regardless of the value of $domain

translators translate the strings

  • which means translators end up translating the same string over and over
  • especially if we use shared libraries ( a la oik ) or Composer dependency

users want the strings translated

  • Users don't really care who did the translation
  • They just want it in their language
  • They do like a bit of consistency
  • And expect translators to be aware of the context when translating.

Use of null text domain

  • If we use oik_require_lib()
  • and the library file knows that translation will be required
  • then we can hook into gettext to provide Just In Time - Just Translate It logic

"Just Translate It" logic

Implemented as a side effect in the oik_l10n_gettext filter function for the gettext filter.

  • Logic lies dormant until it's needed.
  • The first time that a null text domain is encountered the currently loaded domains are merged into the null domain. ( oik_l10n_load_domain )
  • The string is then translated using this domain
  • The logic assumes that the currently loaded domains have been (re)loaded....
  • If switch_to_locale() had been called then we might not have reloaded the domains for all the plugins and themes.
  • If the plugin that's using the library function performs a translation for its own domain before using the shared library then JIT loading should satisfy our requirements.

@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 13, 2017

There are some strings in the shared libraries where applying a translation from another text domain may produce the wrong result. An example is the word Check. In oik-libs source code this word is being used as the verb. In some plugins the word may be used as a noun, being the US spelling of cheque. If a plugin/theme uses this word in that way then, in UK English, we could end up getting an unwanted Cheque. To avoid this situation we should use the _x() function, passing a value for $context which clearly indicates it's not a bank cheque.
e.g. _x( "Check", "examine", null );

We need to test that the correct value is returned when another domain contains the unwanted translation.

@bobbingwide
Copy link
Owner Author

Having reconciled the shared libraries in oik with those in oik-libs most of the Deprecated logic has been catered for except code in libs\class-oik-theme-update.php.
This shared library is used in the genesis-image theme.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant